• 1. 高级软件架构设计康凯 Msn: lptstr512@hotmail.com Mail: lptstr@sina.com1
  • 2. 目录第一单元:软件生命周期与软件架构介绍 2 第二单元:技术架构视图─面向对象程序设计原则与模式 24 用GRASP模式指导设计 27 领域模型 47 面向对象设计的基本原则 71 第三单元:用UML辅助系统分析与设计 103 UML简介及常见疑难问题辨析 104 借鉴RUP的UML建模与分析 117 第四单元:设计模式与软件设计思想 131 设计模式 132 常用的软件架构风格及适用情况分析 172 SOA 及分层架构设计 212 第五单元:架构设计实践 2252
  • 3. 第一单元:软件生命周期与软件架构介绍3
  • 4. IT行业的人才结构与软件架构师的定位 软件架构师应掌握的知识体系 软件架构设计的特点、层次、分类 软件架构的主要理论、方向和趋势 软件工厂,实现软件开发的产业化4
  • 5. 软件架构师的定位系统架构师的职责: 一、理解系统的业务需求,制定系统的整体框架(包括:技术框架和业务框架) 二、对系统框架相关技术和业务进行培训,指导开发人员开发。并解决系统开发、运行中出现的各种问题。 系统架构师的目的: 对系统的重用、扩展、安全、性能、伸缩性、简洁等做系统级的把握。 系统架构师能力要求: 一、系统架构相关的知识和经验。 二、很强的自学能力、分析能力、解决问题的能力。 三、写作、沟通表达、培训。5
  • 6. 角色 软件架构师Software Architect 定义 主导系统全局分析设计和实施、负责软件构架和关键技术决策的角色 6
  • 7. 职责 领导与协调整个项目中的技术活动(分析、设计和实施等) 推动主要的技术决策,并最终表达为软件构架 确定和文档化系统的相对构架而言意义重大的方面,包括系统的需求、设计、实施和部署等“视图” 确定设计元素的分组以及这些主要分组之间的接口 为技术决策提供规则,平衡各类涉众的不同关注点,化解技术风险,并保证相关决定被有效的传达和贯彻 理解、评价并接收系统需求 评价和确认软件架构的实现7
  • 8. 专业技能 技术全面、成熟练达、洞察力强、经验丰富,具备在缺乏完整信息、众多问题交织一团、模糊和矛盾的情况下,迅速抓住问题要害,并做出合理的关键决定的能力。 具备战略性和前瞻性思维能力,善于把握全局,能够在更高抽象级别上进行思考。 对项目开发涉及的所有问题领域都有经验,包括彻底地理解项目需求,开展分析设计之类软件工程活动等。 具备领导素质,以在各小组之间推进技术工作,并在项目压力下做出牢靠的关键决策。 拥有优秀的沟通能力,用以进行说服、鼓励和指导等活动,并赢得项目成员的信任。8
  • 9. 以目标导向和主动的方式来不带任何感情色彩地关注项目结果,构架师应当是项目背后的技术推动力,而非构想者或梦想家(追求完美) 精通构架设计的理论、实践和工具,并掌握多种参考构架、主要的可重用构架机制和模式。 具备系统设计员的所有技能,但涉及面更广、抽象级别更高。 9
  • 10. 软件架构师的知识体系软件架构师作为整个软件系统结构的总设计师,其知识体系、技能和经验决定了软件系统的可靠性、安全性、可维护性、可扩展性和可移植性等方面的性能。因此一个优秀的软件架构师必须具备相当丰富的知识、技能和经验。 通过对比软件架构师和系统分析师在软件开发中的职责和角色,不难发现软件架构师与系统分析师所必需的知识体系也是不尽相同的,系统分析师的主要职责是在需求分析、开发管理、运行维护等方面,而软件架构师的重点工作是在架构与设计这两个关键环节上。因此在系统分析师必须具备的知识体系中对系统的构架与设计等方面知识体系的要求就相对低些;而软件架构师在需求分析、项目管理、运行维护等方面知识的要求也就相对低些。10
  • 11. 成为一名合格的软件架构师必须具备的知识 信息系统综合知识体系 软件架构知识体系11
  • 12. ?MFC,MSF,MOF,RUP,J2EE,Spring,SOA,JUnit,ORM,.Net MVC,UML,XML,Corba,MDA,MDD,Web-Service RSS,Web2.0,AJAX,Serverlet,Hibernate IOC, AOP Ruby On Rails Rup BPEL Workflow Engine LBS Oracle CMMI MQ …12
  • 13. 软件架构师在干什么?思考、思考、再思考 深入理解、准确把握建设的业务需求 分析所有可见的问题、障碍、风险 充分参考已有的成功方案,降低风险 交流、讨论、博弈、质疑 对构思中的方案不断提出质疑,避免漏洞 广泛听取各层面的意见,开拓思路 反复质疑、逐步完善已有的设计构思 在动手实现之前验证设计方案的正确性13
  • 14. 软件架构师的知识结构软件知识 最好要有系统开发全过程经验。 对 IT 建设生命周期各个环节有深入了解,包括:系统/模块逻辑设计、物理设计、代码开发、项目管理、测试、发布、运行维护等。 深入掌握1-2种主流技术平台上开发系统的方法。 了解多种应用系统的结构。 了解架构设计领域的主要理论、流派、框架。 14
  • 15. 软件架构师的知识结构业务知识 深入了解系统建设的业务需求。 了解系统的非功能需求和运行维护需求。 了解企业 IT 公共设施、网络环境、外部系统。 15
  • 16. 软件架构师的思维方式基于框架的思维 架构设计的层次(Enterprise, Application, etc) IT 的生命周期(What, Why, Where, How, When, etc) 成功经验以及方法论的指导 合理把握技术细节 把握各个层次应有的内容 合理忽略不应有的技术细节16
  • 17. 软件架构师的思维方式风险管理意识 采用成功经验、避免不应有的风险 多方位的开放思维 多维度、多方向、包容性、避免排他性 分析、质疑、抽象、归纳 没有绝对好的架构设计,只有相对优秀的方案 17
  • 18. 信息系统综合知识体系(1)计算机系统综合知识:包括计算机组成与体系结构、嵌入式系统和操作系统等方面的知识。 (2)系统配置和方法:包括系统配置技术和系统性能等方面的知识。 (3)典型系统应用:包括网络应用、数据库应用和多媒体系统等方面的知识。 (4)系统开发:包括程序设计语言、软件开发方法、需求分析和设计方法、测试评审方法、开发管理、应用系统构建、系统审计、外部资源使用和基于中间件的开发等方面的知识。 (5)安全性和可靠性技术:包括数据安全与保密、防闯入和防病毒、容错技术、可靠性模型与分析技术、系统可靠性、安全规章和保护私有信息规则等方面的知识。18
  • 19. (6)标准化:包括标准化的基础知识、标准化分级、编码标准、数据交换标准、软件工程标准、信息安全标准、基于构件的软件标准和标准化组织机构等方面的知识。 (7)信息化基础:包括政府信息化与电子政务、企业信息化与电子商务、信息化的有关的法律和规定等方面的知识。 (8)数学和英语:至少具有大学以上的数学和英语基础知识。 19
  • 20. 软件架构知识体系(1)系统计划:包括项目的提出和可行性分析、系统方案的制定、评价和改进、新旧系统的分析与比较、现有软、硬件和数据资源的有效利用等。 (2)软件架构设计:包括软件架构的概念、软件架构与设计、架构风格、特定领域的架构风格、基于架构的软件开发方法、架构评估、软件产品线和系统演化等。 (3)设计模式:包括设计模式的概念、组成、分类和实现、模式和软件架构的关系等。 (4)系统设计:包括处理流程设计、人机界面设计、文件与存储设计、数据库设计、网络应用系统的设计、系统运行环境的集成与设计、中间件与应用服务器、性能设计与性能评估等。 (5)软件建模:包括定义问题与归结模型、结构化系统建模与数据流图、面向对象系统建模、数据库建模和逆向工程等。  20
  • 21. (6)分布式系统设计:包括分布式通信协议的设计、基于对象与web的分布式设计、基于消息和协同的分布式设计和异构分布式系统的互操作性设计等。 (7)嵌入式系统设计:包括实施任务调度和多任务设计、中断处理和异常处理、嵌入式系统开发设计等。 (8)系统可靠性分析与设计:包括系统故障模型和可靠性模型、系统的可靠性分析与可靠度计算、提高系统可靠性的措施、系统的故障对策和系统的备份与恢复等。 (9)系统的安全性和保密性设计:包括系统的访问控制技术、数据的完整性、数据与文件的加密、通信的安全和系统的安全设计等。 (10)复杂架构设计:包括操作系统的架构、编译器的架构和大型基础库的架构等。 21
  • 22. 软件架构师的任职条件根据软件架构师的职责和角色定位,以及知识体系,从实践的角度考虑,合格的软件架构师应该具有以下能力和经验: (1)具有8年以上的软件项目开发实际工作经验,其中至少有3年以上的代码编写工作经验,4年以上的基于面向对象和构件开发方法的软件产品设计经验。 (2)具有5个以上大中型开发项目的总体规划、方案设计经验,有大中型应用系统开发和实施的成功案例。 (3)对相关的技术标准有深刻的认识,对软件工程标准和规范有良好的把握。 (4)对.Net或Java技术及整个解决方案有深刻的理解及熟练的应用,精通Web Service,熟练掌握流行的架构。 22
  • 23. (5)对设计模式有深刻的理解,并能在此基础上设计出适合产品特性和质量属性的框架。 (6)具有面向对象的分析、设计和开发能力,精通UML和XML,能熟练使用Rational Rose、PowerDesigner等工具进行设计。 (7)具有良好的团队意识和协作精神,有较强的沟通能力和书面表达能力。 (8)具有旺盛的精力和学习能力,能快速掌握新技术和新方法。 23
  • 24. 第二单元:技术架构视图─面向对象程序设计原则与模式24
  • 25. 25
  • 26. 26
  • 27. 用GRASP模式指导设计27
  • 28. 28
  • 29. 29
  • 30. 30
  • 31. 31
  • 32. 32
  • 33. 33
  • 34. 34
  • 35. 35
  • 36. 36
  • 37. 37
  • 38. 38
  • 39. 39
  • 40. 40
  • 41. 41
  • 42. 42
  • 43. 43
  • 44. 44
  • 45. 45
  • 46. 46
  • 47. 领域模型47
  • 48. 层次结构 领域模型 从EJB到轻量级框架48
  • 49. 层次结构表现层(present) 业务层 业务层外观 业务层核心 领域对象管理/服务/仓库层 领域对象层 持久层 数据访问层 数据库 49
  • 50. 领域模型中的各种角色: 实体--有唯一的标识,并且要有属性和行为(非GET/SET),添加了行为,使其具有生命力。往往在设计时,实体的形为最难决断。为确定行为,我们必须识别它们的责任和协作。类的责任是指该类要做、知道、或决定的一切,由一个或多个方法完成。类中有属性和关联,协作就是为完成自己的责任所调用其它关联类。 值对象--没有标识没有行为。如Address类。 工厂---定义创建实体的方法,封装实例化对象并将一些关联对象注入。 仓库(repository)管理实体的集合,主要有查找和删除实体的方法.实现类可以调用执久化层(如Hibernate,Ibatis) 服务(Service) ,实现整个应用程序的工作流(workflow)。服务包含那些无法指派的单个实体的行为,由作用于多个对象方法组成。如可以调用repository查找到实体对象,然后委派给这些对象。服务和facade很像,但不一样,它不处理以下事情:1)执行事务。2)收集返回给表现层的数据。3)脱钩对象。4)其它事情。服务可以说是业务的协调者,业务逻辑可以分散到实体对象中。50
  • 51. 领域模型失血模型 贫血模型 充血模型 胀血模型51
  • 52. 失血模型DO只有属性及其getter/setter方法,没有任何业务逻辑。 缺点:行为与数据分离,很多情况导致维护与理解困难。52
  • 53. 贫血模型DO包含不依赖于持久化的领域逻辑;依赖持久化的领域逻辑归入Service层。 Service(业务逻辑,事务封装) DAO DO 优点: 各层单向依赖,结构清楚,易于实现和维护。 设计简单易行,底层模型非常稳定。 缺点: DO部分的持久化逻辑被放入Service层,不够OO。 Service层过重。53
  • 54. 充血模型与贫血模型类似,不同处在于如何划分业务逻辑:绝大多业务逻辑都应该放在DO里(包括持久化逻辑),而Service层很薄,仅仅封装事务和少量逻辑,不和DAO层打交道。 Service(事务封装) DO DAO 优点: 符合OO Service层很薄,只充当Facade的角色,不和DAO打交道。 54
  • 55. 缺点: DAO和DO双向依赖。 如何划分Service层逻辑和Domain层逻辑没有确定的规则,取决与设计人员自己的理解。 Service层封装事务,须对所有的DO逻辑提供相应的事务封装方法,造成重定义所有的Domain logic。 Service的事务化封装的意义等于把OO的Domain logic转换为过程的Service 事务脚本。充血模型在domain层实现的OO在Service层又变成了面向过程。 55
  • 56. 胀血模型取消Service层,只剩下DO和DAO层,在DO的domain logic上面封装事务。 DO(事务封装,业务逻辑) DAO (RoR甚至合并为一层) 优点: 分层简化 符合OO 缺点: service逻辑也强行放入DO ,引起了DO不稳定。 DO暴露给web层过多的信息,可能引起不必要的耦合。56
  • 57. 原则: 业务对象封装了内在的业务逻辑,而应用服务封装了外在于业务对象的业务逻辑。 57
  • 58. EJB到轻量级框架EJB POJO (业务逻辑) + 轻量级框架([Hibernate、JDO、iBATIS](持久化)、Spring(事务管理、安全)) 58
  • 59. EJBEJB: 编写分布式业务应用程序的Java标准架构。 提供大量服务: 声明型事务, EIB容器自动启动、提交和回滚事务。 业务逻辑能参与由远程客户发起的分布式事务。 提供声明型安全,大部分情况下不再摇要编写安全代码求(bean部署描述符里的条目指定准可以防问某个具体bean)。 59
  • 60. 例:在两个账号间进行转账的服务。 60
  • 61. POJO(业务逻辑) +Hiibernate、JDO、iBATIS(持久化)、Spring(事务管理、安全)。 ┏━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━┓ ┃ ┃典型的EJB方法 ┃POJO方法 ┃ ┣━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━┫ ┃组织 ┃过程式业务逻辑 ┃面向对象设计 ┃ ┣━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━┫ ┃实现 ┃基于EJB ┃POJO ┃ ┣━━━━━━━━━╋━━━━━━━━━━━━━━━┻━━━━━━━┫ ┃数据库访问 ┃JDBC/SQL或实体bean ┃持久层框架 ┃ ┣━━━━━━━━━╋━━━━━━━━━━━━━━━┳━━━━━━━┫ ┃返回给表示层的数据┃DTO ┃业务对象 ┃ ┣━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━┫ ┃事务管理 ┃EJB容器管理的事务 ┃Spring框架 ┃ ┣━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━┫ ┃应用程序组装 ┃显式的JNDI查询 ┃依赖注入 ┃ ┗━━━━━━━━━┻━━━━━━━━━━━━━━━┻━━━━━━━┛ 61
  • 62. 新设计是面向对象、基于POJO, 而非基于EJB的过程式。 它使用构建在JDBC上的持久层框架来访问数据库, 并不直接使用JDBC。 业务逻辑由POJO facade而非会话bean进行封装。 事务由Spring框架而非EJB容器进行管理。 业务逻辑向表现层返回实际的业务对象,而不是DTO。 应用程序通过将组件的依赖作为setter或构造子参数传入来进行组装,而不是之前采用Java命名和目录接口(JNDI )查询的组件。 由于该设计面向对象,并采用上述轻量级技术,因此较之前看到的EJB版本对开发人员要友好。62
  • 63. 基于轻量级框架设计的好处是,它提供事务和持久化时并不要求应用程序类实现任何特殊接口。甚至当应用程序的类需要运行在事务里或是持久的时候,它们仍是POJO,设计者可以继续享受POJO的种种好处。63
  • 64. 64
  • 65. 面向对象的优点: 整个设计更易理解和维护。它并不是一个无所不能的大型类, 而是由大量小类组成, 每个类只共有若干职责。此外,诸如Account、BankingTransaction和OverdraftPolicy类都与现实世界的概念对应, 因此易于理解。 其次,面向对象设汁也更易测试: 所有类都能并且应当进行独立的测试。EJB只能通过调用它的public 方法如Transter进行测试,难度大。(只能测试p-blic方法暴露的复杂功能,无法测试其中简单的部分)。 面向对象象设计更易扩展, 它可使用设计模式,如Stategy和Template等。EJB风格的过程式设计往往需耍修改核心代码。65
  • 66. 不适合用面向对象的场合: 大量数据集合的关系操作。 以数据库为中心的管理程序 :这个领域所对应的现实世界是一个面向关系的世界,表与表的关联体现的是彼此的业务关系。 复杂的SQL固然不好维护,但业务真是复杂到简单的SQL都难以描述的程度,采用面向对象描述则更加困难,维护也更困难,同时还损失了效率。 比较大的事务。 性能要求高的地方。(直接用Sql或者存储过程;牺牲可维护性和可复用性) 上层流程。66
  • 67. 消除DTO67
  • 68. 部署POJO程序68
  • 69. 69
  • 70. 70
  • 71. 面向对象设计的基本原则71
  • 72. 72
  • 73. liskov替换原则(LSP)73
  • 74. 子类型必须能够替换掉其基类型问题的根源是关于行为的: 基类中有的行为在子类中不存在或不适当。 IS A的本质是指行为的一致,而不是生活中的语言。 违反了LSP原则的本质是派生类的行为与基类中的不一致。 如果违反了LSP原则,常会导致在运行时的类型判断(RTTI)违反OCP原则。 例如:函数A的参数是基类型,调用时传递的对象是子类型,正常情况下,增加子类型都不会影响到函数A的,如果违反了LSP,则函数A必须小心的判断传进来的具体类型,否则就会出错,这就已经违反了OCP原则。74
  • 75. 违反LSP导致违反OCP的简单例子75
  • 76. 改善76
  • 77. 例:会议管理系统77
  • 78. 例:GUI对象假定一个Component代表一个GUI对象,如按钮或者文本框等。78
  • 79. 79
  • 80. 80
  • 81. 改善281
  • 82. 例82
  • 83. 接口隔离原则(ISP)康凯83
  • 84. 例84
  • 85. 使用委托分离接口85
  • 86. 使用多重继承分离接口86
  • 87. 内接口与外接口87
  • 88. 普通接口与智能接口88
  • 89. 软件系统坏死的症状89
  • 90. “Copy”程序一个从键盘读入字符并输出到打印机的程序。 void Copy() { int c; while ((c = RdKbd()) != EOF) WrtPtr(c); }90
  • 91. 需求在变化用户希望Copy程序能从纸带读入机中读入信息。 现实中的约束--不能改变接口 Copy程序的第一次修改结果 bool ptFlag = false; //remember to reset this flag void Copy() { int c; while ((c = (ptFlag ? Rdpt() : Rdkbd())) != EOF) WrtPtr(c); }91
  • 92. 需求在变化2客户希望Copy程序有时可以输出到纸带穿孔机上。 //Copy程序的第二次修改结果 bool ptFlag = false; bool punchFlag = false; //remember to reset these flag void Copy() { int c; while ((c = (ptFlag ? Rdpt() : Rdkbd())) != EOF) punchFlag ? WrtPunch(c) : WrtPtr(c); } 92
  • 93. 依赖倒置原则(DIP)康凯93
  • 94. 相关概念关于解耦 依赖倒置(DIP) 控制反转(IoC) 依赖注入(DI) 服务定位器(SL) 有些是手段,有些是原则,不过其间的差异并不太重要,更重要的是其共同点:其根本目标都是解除依赖,将组件的配置与使用分离开。 其它名词 服务 组件 框架 类库 应用程序94
  • 95. 接口和实现分离 面向过程的接口与实现分离95
  • 96. 96
  • 97. 97
  • 98. 98
  • 99. 电影清单的例子一个组件,用于提供一份电影清单,清单上列出的影片都是由一位特定的导演执导的。 class MovieLister { ... public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll(); for (Iterator it = allMovies.iterator(); it.hasNext();) { Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove(); } return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); } } 99
  • 100. 其中真正想要考察的是如何将MovieLister对象与特定的finder对象连接起来。 要求:我们希望moviesDirectedBy方法完全不依赖于影片的实际存储方式。 这个方法只能引用一个finder对象, 而finder对象必须知道如何实现findAll的细节。 给finder定义一个接口: public interface MovieFinder { List findAll(); } 当要实际寻找影片时,就必须涉及到MovieFinder 的某个具体子类。在这里,我把“涉及具体子类”的代码放在MovieLister 类的构造函数中。100
  • 101. 对抗变化从一个逗号分隔的文本文件中获得影片列表。 class MovieLister... private MovieFinder finder; public MovieLister() { finder = new ColonDelimitedMovieFinder("movies1.txt"); } 对抗变化: 文件清单的名字更改: 可以从一个配置文件获得文件名。 如果用SQL 数据库、XML 文件、web service,或者另一种格式的文本文件来存储影片清单: 用另一个具体的类来获取数据。该类从MovieFinder接口派生即可。 创建合适的MovieFinder派生类的实例: 不能对抗此变化。101
  • 102. 配置文件设定配置文件:XML 文件是比较理想的配置方式。 movies1.txt 102
  • 103. 第三单元:用UML辅助系统分析与设计103
  • 104. UML简介及常见疑难问题辨析104
  • 105. UML用来描述模型的内容有3种,分别是事物( Things )、关系Relationships )和图( Diagrams )。 105
  • 106. UML中的关系UML中的关系(Relationships )主要包括4种: 1、关联关系 2、依赖( Dependency)关系 3、泛化( Generalization )关系 4、实现( Realization )关系106
  • 107. 一些常见问题辨析类的层次结构表示 属性与聚合 关联角色 关联类107
  • 108. 层次结构108
  • 109. 领域建模-重数109
  • 110. 细化类模型110
  • 111. 关联角色关联角色名出现在关联终端的旁边。当仅仅使用关联名不足够表达清楚后,可以用关联角色名来加强表达。 可以把每个名称都当成伪属性,关联角色名提供了一种可以遍历关联的方法。111
  • 112. 在创建类图时,应该为使用正确的角色名,而不是为每个引用引入一个独立的类。 因为角色名可以区分对象,所以附在一个类上的关联名必须唯一(可以把角色名想象成类的伪属性)。同样,角色名不应该与类的属性名重复。112
  • 113. 关联类正如可以用属性描述类的对象一样,也可以用属性来描述关联的链接,可以把这样的一组属性组成关联类。 113
  • 114. Actor的一些注意事项包括人与系统,总是外部的。 定义了边界。 Actor是“角色”,不是特定的人或特定的事。 要有恰当的名字。 可以泛化 不是可有可无的东西。另一方面它可以划分系统与外部实体的界限,是系统设计的起点。114
  • 115. 用例的一些注意事项是需求分析的第一步。用户首先关心功能。 用例是对一个系统或一个应用的一种单一的使用方式所作的描述,是关于单个活动者在与系统对话中所执行的处理行为的陈述序列。 不是事件流。 不是需求规格说明,但反映了主要的功能性需求。 识别用例最好是从分析流开始。 每个用例都是独立的。 用例名用动宾结构描述,不要写成一个名词。 用例是分层的,一般而言,高层/中层用例更有实际意义。 不要将不同的用例混合在一起。 用例与编码:低层的用例可以辅助编码,高层的不能。 扩展用例:基础用例不必知道扩展用例的细节,只提供扩展点。115
  • 116. 仓库信息系统的用例图116
  • 117. 借鉴RUP的UML建模与分析 117
  • 118. 全局分析全局分析侧重于定义拟建系统所采用的构架以及影响构架的要素。全局分析充分利用相似或问题中的经验,避免在确定构架上浪费人力和物力。 选用架构模式 识别关键抽象:寻找那些无论在问题域或方案领域都具有普遍意义的概念点。 标识分析机制:将那些问题领域(应用逻辑)没有直接关联的计算机概念及相应的复杂行为表述为支撑分析工作的“占位符”。 选定分析局部:针对拟建系统的整体架构,找出那些蕴含相对高风险的局部作为工作内容。118
  • 119. 全局分析常见的分析机制 留存 分布式处理 安全性 进程间通信 消息路由 进程控制与同步 交易事务管理 信息交换 信息的冗余 错误检测、处理和报告 数据格式转换119
  • 120. 局部分析提取分析类 转述需求场景 整理分析类120
  • 121. 局部分析分析类的类型划分 众多实践表明,如果立足于软件功能需求,拟建系统往往在三个维度易于发生变化:一、拟建系统和外部要素之间交互的边界;第二,拟建系统要记录和维护的信息;第三,拟建系统在运行中的控制逻辑。通常按照这三个变化因素的维度,将分析类划分为三种类型:边界类、控制类、实体类系统边界Use Case 行为协调基本信息121
  • 122. 局部分析122
  • 123. 局部分析123
  • 124. 局部分析124
  • 125. 局部分析整理分析类 分析类是这样的类:它代表问题域中的简洁抽象; 分析类映射到真实世界的业务概念(并且据此仔细命名)。 问题域是首先产生软件系统(以及从此而来的软件开发活动)需求的域。通常,这是特定的业务领域,如在线销售或者客户关系管理。然而,务必注意,问题域可能根本不是任何特定业务活动,但 是可能产生需要软件在其上运转的一块物理硬件─这是嵌入式系统。基本上,所有业务软件开发服 务于某种业务需求,自动化一个已有业务过程或者开发具有有意义的软件组件的新产品。125
  • 126. 分析类的职责职责是类和它的客户之间的契约或者是类对它的客户的义务。本质上,职责是类提供给其他类的 服务。分析类具有直接同类(由它的名称所表达)的目的相一致的以及直接同该类正在建模的真实世 界“事物”相一致的非常内聚的职责集合,这一点是至关重要的。例如ShoppingBasket示例,你将期 望该类具有如下职责: 向购物篮添加商品; 从购物篮删除商品; 显示购物篮中的商品。 这是内聚的职责集合,一切都是为了维护客户选择的商品集合。它是内聚的,因为所有的职责都朝着相同的目标─维护客户已经选择的商品集合。实际上,我们能够把这些职责概括为非常高级层 次的职责“维护购物篮”。 同样,向 ShoppingBasket 中添加如下职责:126
  • 127. 分析类的职责验证信用卡; 接收付款; 打印收据。 但这些职责似乎同购物篮的目的或直觉语法不匹配。它们不是内聚的,显然应该赋予其他什么类─ 可能是类CreditCardCompany、类Checkout以及类ReceiptPrinter。把职责适当地分配给分析类 以最大化每个类中的内聚性,是很重要的。 最后,良好的类与其他类之间具有最低数目的耦合。我们以给定类与其他类具有关系的数目来度量类间的耦合度。类间职责的平均分布趋向于产生低耦合度。把控制或职责局限于单一的类趋向于增 加到该类的耦合度。 127
  • 128. 分析类经验法则以下是创建形式良好的分析类的一些经验法则。 每个类大约3~5个职责─典型地,类应该保持尽可能简单,这通常限制类能够支持的3~5个职 责的数目。先前ShoppingBasket 的示例是带有小的和可管理数目职责的专注的类的好的示例。 不存在独立的类─好的OO分析和设计的精华是,类相互协作让用户受益。同样,每个类应该 同小部分类协作以提供所期望的功能。类可以把它们的一些职责托付给专注于特定功能的其他“辅助”类。 当心很多非常小的类─ 有时很难取得正确的平衡。如果模型看起来具有大量的非常小的类, 每个类都具有一个或者两个职责,那么你应该仔细查看以把一些小的类整合成更大的类。128
  • 129. 当心少数几个非常庞大的类─上述的反面是,模型具有很少的类,但每个类都是具有职责数 量(>5)的庞大的类。解决问题的策略是依次查看这些类,看看是否每个类都能够被分解成为 两个或者多个能够承担恰当数目职责的、更小的类。 当心“伪类”─伪类其实是一般的过程函数,它伪装成类。 当心万能类─ 存在似乎能够承担任何工作的类。看看名称为“system”和“controller”的 类!处理这个问题的策略是看看万能类的职责是否能够分解成内聚的子集。如果是,每个这些 内聚职责集合可能独立成类。这些更小的类协作以实现由原始万能类所提供的行为。 129
  • 130. 分析类经验法则避免深度继承树─设计良好的继承层次的本质是继承层次中每个抽象层次应该具有良好定义 的目的。容易添加很多实际上不能服务于任何目的层次。 实际上,通常的错误是使用继承来实 现一种功能分解,其中每个抽象层次恰有一个职责! 无论从哪个方面来讲,这都是无意义的,是会导致复杂的、难以理解的模型。 在分析中,类代表业务事物,而业务事物趋向于形成更宽(不超过三层)的继承层次。 我们把三层或者更多层次的继承认为是“深度”继承。 130
  • 131. 第四单元:设计模式与软件设计思想131
  • 132. 设计模式132
  • 133. 设计模式在实际开发中的运用复用现有的、高质量的、针对常见的重复出现问题的解决方案。 建立通用的术语以改善团队内部的沟通。 将思考转移到更高的视角。 判断是否拥有正确的设计,而不仅仅使一个可以运行的设计。 改善代码的可修改性。 发现“庞大的继承体系”的替代方案。133
  • 134. GoF中的模式分类134
  • 135. 设计模式的特点设计模式最根本的意图是适应需求变化 隔离变化的部分与不变的部分,将之封装起来。 针对接口编程,而不要针对实现编程 达成高内聚合低耦合,提高复用 提倡优先使用聚合,而不是继承135
  • 136. 例一个日志记录工具。目前需要提供一个日志API,提供客户方便地调用。 该日志要求被记录到指定的文本文件中,记录的内容属于字符串类型,其值由客户提供。 可以容易地定义一个日志对象。 public class Log { public void Write(string target, string log) { //实现内容; } } 当客户需要调用日志的功能时,可以创建日志对象,完成日志的记录: Log log = new Log(); log.Write(“error.log”, “log”);136
  • 137. 137
  • 138. 138
  • 139. 例我们需要设计一个数据库组件,它能够访问Sql Server数据库。如果用ADO.Net,需要使用如下的对象: SqlConnection, SqlCommand, SqlDataAdapter等。 不用模式的做法:可以直接创建这些对象: SqlConnection connection = new SqlConnection(strConnection); SqlCommand command = new SqlCommand(connection); SqlDataAdapter adapter = new SqlDataAdapter(); 139
  • 140. Connection对象: 140
  • 141. 141
  • 142. 策略(Strategy)模式142
  • 143. 练习下面是一堆杂乱的类与接口: 动作冒险游戏。包括代表游戏角色的类,以及武器行为的类。每个角色一次只能使用一个武器,但是可以在游戏的过程中换武器。 任务: 1.安排类。 2.找出一个抽象类、一个接口、以及八个类。 3.在类之间画箭头。 A.继承。B.实现接口。C.「有一个」关系。 4. 把setWeapon() 方法放到正确的类中。143
  • 144. 原始的类与接口144
  • 145. 例:电子零售系统该电子零售系统必须处理来自不同国家的销售定单。例如在美国与加拿大。需求如下: 请况过程美国据UPS的价格计算运费 使用美国邮政规则检查地址 根据销售额或服务,按照当地税收规则计算税费金额 使用美元处理款项加拿大根据主要的加拿大托运公司的价格计算运费 使用加拿大邮政规则检查地址 根据销售额或服务,按照加拿大各省的税收规则计算税费金额(GST和PST) 使用加拿大元处理款项145
  • 146. 分析矩阵146
  • 147. 桥接(Bridge)模式147
  • 148. 意图 “将抽象部分与它的实现部分分离,使它们都可以独立地变化”。 抽象部分是指“不同的事物在概念层次上的联系”。分离是指“让各部分的行为各自独立,或至少显式指出关联”。148
  • 149. 例通过引入一个Rectangle 抽象类,利用了这一事 实:不同的Rectangle派 生类之间唯一的差异是如 何实现drawLine方法。 V1Rectangle类的实现方 式是:保存一个DP1对象 的引用,使用DP1对象的 draw_a_line方法。 V2Rectangle类的实现方 法是:保存一个DP2对象 的引用,使用这个对象的 drawline方法。149
  • 150. 需求变化用户要求支持另一种形状——圆形。150
  • 151. 识别变化首先识别出“什么在发生变化”。在上述的例子中,变化点是“不同类型的形状”和“不同类型的画图程序”。共同的“概念”则是“形状”和“画图程序”。 用Shape类来封装拥有的形状的概念。形状有责任知道如何画自己。Drawing对象负责画线和圆。 151
  • 152. 描述变化下一步是描述出现的特定变化:Shape类拥有矩形和圆形。画图程序分别拥有一个基于DP1的对象(V1Drawing)和一个基于DP2的对象(V2Drawing)。152
  • 153. 桥接模式153
  • 154. 观察者(observer)模式康凯154
  • 155. 155
  • 156. 命令(command)模式康凯156
  • 157. 意图 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。 别名 动作(Action),事务(Transaction) 动机 有时必须向某对象提交请求,但并不知道关于被请求的操作或请求的接受者的任何信息。 例如,用户界面工具箱包括按钮和菜单这样的对象,它们执行请求响应用户输入。但工具箱不能显式的在按钮或菜单中实现该请求,因为只有使用工具箱的应用知道该由哪个对象做哪个操作。而工具箱的设计者无法知道请求的接受者或执行的操作。命令模式通过将请求本身变成一个对象来使工具箱对象可向未指定的应用对象提出请求。这个对象可被存储并像其他的对象一样被传递。这一模式的关键是一个抽象的Command类。157
  • 158. 例子158
  • 159. 结构159
  • 160. 其它设计模式160
  • 161. VISITOR模式 该系列中的模式如下: VISlTOR模式 ACYCLIC VISITOR模式 DECORATOR模式 EXTENSION OBJECT模式161
  • 162. 例是一个常见的问题:例如,有一个Modem对象的层次结构。基类中有所有调制解调器的公共方法。派生类代表不同调制解调器类型的驱动程序。162
  • 163. 问题假设需要向该层次结构中增加一个新方法confrgureForUnix。使之可在UNIX下工作。在每个调制解调器派生类中该函数的实现都不相同。(假设每个不同的调制解调器在UNIX中都有自己独特的配置方法和行为特征)。 问题:直接增加configureForUnix方法其实回避了一个问题:对于Windows如何处理? MacOS? Linux? 必须针对所使用的每一种新操作系统都要向Modem层次结构中增加一个新方法? 这种做法是丑陋的:我们永远无法封闭Modem接口。每当出现一种新操作系统时, 就必须更改该接口并重新部署所有的调制解调器软件。 163
  • 164. VISITOR模式的结构164
  • 165. VISITOR+组合模式VISTTOR模式的一个非常常见的应用是,遍历大量的数据结构并产生报表。这使得数据结构对象中不含有任何产生报表的代码。如果想增加新报表,只需增加新的访问者,而不需要更改数据结构中的代码。这意味着报表可以被放置在不同的组件中,并且仅被那些需要它们的客户单独使用。165
  • 166. 例:报表生成器一个表示材料单的简单数据结构。从该数据结构可以生成无数的报表。 两个可以统计的量:成本;数量 例如可以生成一张一个组合件总成本的报表,或者生成一张列出了一个组合件中所有零件的报表。 166
  • 167. VlSITOR模式的解决方法167
  • 168. 其它模式问题: 考虑前面的Modem层次结构。假设有一个具有很多使用者的应用程序。每个使用者都可以坐在他的计算机前,要求系统使用该计算机的调制解调器呼叫另一台计算机。有些用户希望听到拨号声,有些用户则希望他们的调制解调器保持安静。 168
  • 169. DECORATOR模式DECORATOR模式通过创建一个名为LoudDialModem的全新类来解决这个问题。 LoudDialModem派生自Modem ,并且委托给一个它包含的Modem实例。它捕获对dial函数的调用并在委托前把音量设高。169
  • 170. 多个Decorator有时,在同一个类层次结构中可能存在两个或者更多的装饰器(decorator)。 例如, 可能希望用LogoutExitModem来装饰Modem层次结构, 当Hangup被调用时,它会发送字符串 "exit"。这个装饰器必须要重复已经在LoudDialModem中编写过的所有委托代码。170
  • 171. 171
  • 172. 常用的软件架构风格及适用情况分析 康凯172
  • 173. 软件架构 软件框架 常见的架构风格 173
  • 174. 软件架构概论系统架构是一个软件系统从整体到部分的最高层次的划分。 一个系统通常是由元件组成的,而这些元件如何形成、相互之间如何发生作用,则是关于这个系统本身结构的重要信息。 详细地说,就是要包括架构元件(Architecture Component)、联结器(Connector)、任务流(Task-flow)。所谓架构元素,也就是组成系统的核心"砖瓦",而联结器则描述这些元件之间通讯的路径、通讯的机制、通讯的预期结果,任务流则描述系统如何使用这些元件和联结器完成某一项需求。174
  • 175. 建造一个系统所作出的最高层次的、以后难以更改的,商业的和技术的决定。 在建造一个系统之前会有很多的重要决定需要事先作出,而一旦系统开始进行详细设计甚至建造,这些决定就很难更改甚至无法更改。显然,这样的决定必定是有关系统设计成败的最重要决定,必须经过慎重的研究和考察。 175
  • 176. 架构的目标可靠性(Reliable): 软件系统对于用户的商业经营和管理来说极为重要,因此软件系统必须非常可靠。 安全性(Secure) : 软件系统所承担的交易的商业价值极高,系统的安全性非常重要。 可伸缩性(Scalable) : 软件必须能够在用户的使用率、用户的数目增加很快的情况下,保持合理的性能。只有这样,才能适应用户的市场扩展得可能性。 176
  • 177. 架构的目标可定制化(Customizable) : 同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整。 可扩展性(Extensible): 在新技术出现的时候,一个软件系统应当允许导入新技术,从而对现有系统进行功能和性能的扩展 可维护性(Maintainable): 软件系统的维护包括两方面,一是排除现有的错误,二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费。177
  • 178. 客户体验(Customer Experience): 软件系统必须易于使用。 市场时机(Time to Market): 软件用户要面临同业竞争,软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。178
  • 179. 架构的种类根据我们关注的角度不同,可以将架构分成三种: 逻辑架构 物理架构 系统架构179
  • 180. 逻辑架构软件系统中元件之间的关系,比如用户界面,数据库,外部系统接口,商业逻辑元件等等。 180
  • 181. 物理架构软件元件是怎样放到硬件上的 下图描述了一个分布于北京和上海的分布式系统的物理架构,图中所有的元件都是物理设备,包括网络分流器、代理服务器、WEB服务器、应用服务器、报表服务器、整合服务器、存储服务器、主机等等。181
  • 182. 系统架构系统的非功能性特征,如可扩展性、可靠性、强壮性、灵活性、性能等。 系统架构的设计要求架构师具备软件和硬件的功能和性能的过硬知识,这一工作是架构设计工作中最困难的工作。182
  • 183. 架构的两要素元件划分和设计决定。 逻辑元件: 一个软件系统中的元件首先是逻辑元件。这些逻辑元件如何放到硬件上,以及这些元件如何为整个系统的可扩展性、可靠性、强壮性、灵活性、性能等做出贡献,是非常重要的信息。 设计决定: 进行软件设计需要做出的决定中,必然会包括逻辑结构、物理结构,以及它们如何影响到系统的所有非功能性特征。这些决定中会有很多是一旦作出,就很难更改的。 基于数据库的系统架构: 一般有多少个数据表,就会有多少页的架构设计文档。比如一个中等的数据库应用系统通常含有一百个左右的数据表,这样的一个系统设计通常需要有一百页左右的架构设计文档。183
  • 184. 软件框架什么是框架 框架与架构的区别 常见的框架184
  • 185. 框架什么是框架? 框架,即framework。是某种应用的半成品,就是一组组件,供选用完成自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。 框架与架构的区别? 并无明确的定义,但一般从层的观点看,认为框架是底层的,接近系统的。软件开发者在其上构建自己的软件架构,开发自己的运用程序。185
  • 186. 为什么要用框架因为软件系统发展到今天已经很复杂了,特别是服务器端软件,设计到的知识,内容,问题太多。在某些方面使用成熟的框架,可以避免重复做已有的基础工作,而只需要集中精力完成系统的业务逻辑设计。 框架一般是成熟,稳健的,可以处理系统很多细节问题,比如,事物理,安全性,数据流控制等问题。 框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,使用框架的开发者可以直接享受别人升级代码带来的好处。 框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。 186
  • 187. 常见的框架常见的JAVA框架 常见的.Net框架 其它基于C++的框架187
  • 188. 常见的JAVA框架EJB WAF Struts Turbine COCOON ECHO JATO TCF Spring Hibernate IBatis JSF 188
  • 189. .NET 框架.NET 框架是创建、部署和运行 Web 服务及其他应用程序的一个环境。它包括三个主要部分:公共语言运行时、框架类和 ASP.NET。 .NET 框架对 Web 站点的支持: ASP.NET 在编写 Windows 软件(使用 ATL/COM、MFC、VB或标准 Win32)方面,与当前创建应用程序的方式相比.NET都具有的优势。 189
  • 190. C++框架ACE BOOST MFC ATL QT wxWidgets …190
  • 191. 不同层次的模式架构模式(Architectural Pattern) 设计模式(Design Pattern) 代码模式(Coding Pattern)191
  • 192. 区别:在于三种不同的模式存在于它们各自的抽象层次和具体层次。 架构模式是一个系统的高层次策略,涉及到大尺度的组件以及整体性质。架构模式的好坏可以影响到总体布局和框架性结构。 设计模式是中等尺度的结构策略。这些中等尺度的结构实现了一些大尺度组件的行为和它们之间的关系。模式的好坏不会影响到系统的总体布局和总体框架。设计模式定义出子系统或组件的微观结构。 代码模式是特定的范例和与特定语言有关的编程技巧。代码模式的好坏会影响到一个中等尺度组件的内部、外部的结构或行为的底层细节,但不会影响到一个部件或子系统的中等尺度的结构,更不会影响到系统的总体布局和大尺度框架。192
  • 193. 几种典型的架构模式系统软件 分层(Layer) 管道和过滤器(Pipes and Filters) 黑板(Blackboard) 开发分布式软件 经纪人(Broker) 客户/服务器(Client/Server) 点对点(Peer to Peer) 交互软件 模型-视图-控制器(Model-View-Controller) 显示-抽象-控制(Presentation-Abstraction-COntrol)193
  • 194. 其它面向对象风格(ADT) 基于消息广播且面向图形用户界面的Chiron2风格 基于事件的隐式调用风格(Event-based, Implicit Invocation) … 194
  • 195. 分层(Layer)从不同的层次来观察系统,处理不同层次问题的对象被封装到不同的层中。 软件为什么要分层? 为了实现“高内聚、低耦合”。把问题划分开来各个解决,易于控制,易于延展,易于分配资源… 面向对象的、基于模块化的组件设计需要能够方便地修改应用程序的各个部分。完成这一目标的一种好方法就是在层上工作,将一个应用程序的主要功能分离到不同的层或者级中。195
  • 196. 分层模型从本质上讲,层代表了一个应用程序主要的功能。一般地,我们将应用程序功能分为三个方面,对应3层架构模式。它们是数据层(data layer)、商务层(business layer)和表示层(presentation layer)。 数据层:包含数据存储和与它交互的组件或服务。这些组件和服务在功能上和中间层相互独立(尽管在物理上不必一定相互独立--它们可以在同一台服务器上)。 中间层:包括一个或者多个组件服务,它们应用商务规则、实现应用程序逻辑并完成应用程序运行所需要的数据处理。作为这个过程的一部分,中间层负责处理来自数据存储或者发送给数据存储的数据。 196
  • 197. 表示层:从中间层获得信息并显示给用户。该层同时也负责和用户进行交互,比较返回的信息并将信息回送给中间层进行处理。 数据层从数据库中获得较为原始的数据,商务层把数据转换成符合商务规则的有意义的信息,表示层把信息转换成对于用户有意义的内容。 这种分层设计方式很有用,因为每一层都可以独立地修改。我们可以修改商务层,不断地从数据层接受相同的数据,并把这些数据传递到表示层,而不用担心出现歧义。我们也可以修改表示层,使得对于站点外观的修改不必改动下面的商务层逻辑。197
  • 198. 管道和过滤器(Pipes and Filters)管道和过滤器架构模式是为处理数据流的系统提供的一种模式。它是由过滤器和管道组成的.每个处理步骤都被封装在一个过滤器组件中,数据通过相邻过滤器之间的管道进行传输。每个过滤器可以单独修改,功能单一,并且它们之间的顺序可以进行配置。 198
  • 199. 一个著名的例子是传统的编译器。传统的编译器一直被认为是一种管道系统,在该系统中,一个阶段(包括词法分析、语法分析、语义分析和代码生成)的输出是另一个阶段的输入。 199
  • 200. 问题: 一个必须处理或转换输入数据流的系统。把这样的系统作为单个组件实现是不容易的: 系统必须由几个开发人员同时进行协作开发,整个系统任务自然就被分解为几个处理阶段,而且需求很容易变动。因此你就要通过替换或重新排序处理步骤来为将来的灵活性作规划。通过加入这样的灵活性,采用现有处理组件构建是可以办到的。 系统的设计尤其是处理步骤的内部连接,必须考虑以下因素: 未来系统的升级通过替换某些处理步骤,或重组步骤。 不同的语境中小的处理步骤要比大的组件更易于重用。 不相连的处理步骤不可共享信息。 存在不同的输入数据源,可以用多种方式输出或存放最终结果。200
  • 201. 解决方案与结构管道和过滤器体系架构模式把系统任务分成为几个独立的处理步骤。这些步骤采用通过系统的数据流连接。一个步骤的输出是下一个步骤的输入。每个处理步骤由一个过滤器组件实现,它处理或者转化数据,并且系统的输入可以是多种数据源。 这种体系架构模式具有许多特性: 过滤器是独立运行的部件。也就是除了输入和输出外,每个过滤器不受任何其他过滤器运行的影响。在设计上,过滤器之间不共享任何状态信息。 独立性还表现在它对其处理的上游和下游连接的过滤器是"无知"的.它的设计和使用不对与其连接的任何过滤器施加限制,唯一关心的是其输入数据的,然后进行加工处理,最后产生数据输出。201
  • 202. 优点与缺点优点: 结构简单:系统的行为是所有过滤器行为的简单复合。 系统易于维护和增强:增加新过滤器,替换旧过滤器。 支持复用:过滤器只同其输入、输出端口的数据相关。 各过滤器可以并发运行。 缺点: 容易导致批处理方式:每个过滤器从输入数据到输出数据的转换是一个整体。转换通常不适合交互式的应用。 有时必须维护两个分离而又相关的流之间的对应关系。 同实现有关,过滤器之间的数据传输率较低,而且每个过滤器都要作类似的数据打包和解包的工作。202
  • 203. 黑板(Blackboard)又称看板模式:在这种架构中,有两种不同的构件:一种是表示当前状态中心数据结构;另一种是一种相互独立的构件,这些构件对中心数据进行操作。这种架构主要用于数据库和人工智能系统的开发。 模式识别、数据挖掘。203
  • 204. 经纪人(Broker)客户和服务器通过一个经纪人部件进行通信,经纪人负责协调客户和服务器之间的操作,并且为客户和服务器发送请求和结果信息。204
  • 205. 代理程序驻留在一个不应该频繁更改的、众所周知的位置。已被激活并且准备接收请求的任何服务器都将向代理程序注册自己,以便下一次客户端向代理程序请求这种类型的服务器时,代理程序能够使用它。这还可能提高系统的性能和可用性,因为它使您可以拥有多个同时运行并服务于多个客户端的、完全相同的服务器组件。这种机制有时称为负载平衡。205
  • 206. 客户/服务器(Client/Server)系统分为客户和服务器,服务器一直处于侦听的状态,客户主动连接服务器,每个服务器可以为多个客户服务。206
  • 207. 优缺点优点: 结构简单,系统中不同类型的任务分别由客户和服务器承担,有利于发挥不同机器平台的优势; 支持分布式、并发环境,特别是当客户和服务器之间的关系是多对多时,可以有效地提高资源的利用率和共享程度; 服务器集中管理资源,有利于权限控制和系统安全。 缺点: 在大多数client-server风格的系统中,构件之间的连接通过(远程)过程调用,接近于代码一级,表达能力较弱。207
  • 208. 点对点(Peer to Peer)系统中的节点都处于平等的地位,每个节点都可以连接其他节点。在这种架构中,一般需要由一个中心服务器完成发现和管理节点的操作。ICQ以及Web Service技术的大多数应用,都是典型的点对点结构。 208
  • 209. 模型-视图-控制器(MVC)当应用程序的用户界面非常复杂,且关于用户界面的需求很容易变化时,我们可以把交互类型的软件抽象成模型、视图和控制器这三类组件单元,这种抽象可以很好地分离用户界面和业务逻辑,适应变化的需求。大多数现代交互软件都在一定程度上符合这一架构模型的特点。 MVC模式最吸引人之处在于它迫使用户必须抽象自己的代码,把项目分为表示、逻辑和控制三部分,每部分间的关联较小。 以MVC模式构造软件,可以使得软件结构灵活、重用性好、扩展性佳。 209
  • 210. 模型—视图—控制器交互的示意图210
  • 211. 模型:视图:控制器:模型: 模型表示应用的数据及操作这些数据的逻辑方法。任何和整个应用有关的持久性数据都应该放在模型中。对于模型,它所提供的API不能只针对某一个专门的视图或控制器,应该更一般化以适应不同客户的需求。 视图: 视图将模型的当前状态展示给用户,具体的显示方法由视图负责,因此一个模型可以适用多个不同的视图。在模型状态改变后,通过模型和视图之间的协议,视图得知这种改变并修改自己的显示。对于用户的输入,视图将它们交给控制器处理。 控制器: 控制器负责交互和将用户输入的数据导入模型,它还利用用户的输入将应用转向其他视图。一些非持久的临时数据也应该在视图中存取。211
  • 212. SOA 及分层架构设计212
  • 213. SOA的架构的特点服务(Service) 定义良好的,自包含的,不依赖于上下文和其它服务的一组功能 SOA(Service-Oriented Architecture) 本质上是一组服务的集合 服务之间相互沟通 可以是简单的数据传输,或者是由两个或多个服务共同参与的一些活动,SOA也包括Service之间的连通技术。213
  • 214. OO vs. SOA –OO的扩展遇到了挑战 随着时间的推移,接口继承的复杂度在累积 随着系统间距离的延伸,调用成本在上升,类型系统的不同步 扩展组件的功能成本高,不可确定未来需求,不可堆叠的扩展方式 重用与标准化,重用是OO的第一原则,难以维持和维护复杂的重用标准和机制214
  • 215. –OO vs. SOA OO仍然适用于服务的开发 明显的性能优势 成熟的设计与开发方法 SOA适用于系统的互联 互操作性的要求强于性能的要求215
  • 216. SOA 既不是一种语言,也不是一种具体的技术,它是一种新的软件系统架构模型。 SOA 最主要的应用场合在于解决在Internet环境下的不同商业应用之间的业务集成问题。 SOA 架构的出现为企业系统架构提供了更加灵活的构建方式,如果企业架构设计师基于 SOA 来构建系统架构,就可以从底层架构的级别来保证整个系统的松耦合性以及灵活性,这都为未来企业业务逻辑的扩展打好了基础。 216
  • 217. 特性: 松耦合性 松耦合性要求 SOA 架构中的不同服务之间应该保持一种松耦合的关系,也就是应该保持一种相对独立无依赖的关系; 位置透明性 位置透明性要求 SOA 系统中的所有服务对于他们的调用者来说都是位置透明的,也就是说每个服务的调用者只需要知道他们调用的是哪一个服务,但并不需要知道所调用服务的物理位置在哪里; 协议无关性。 协议无关性要求每一个服务都可以通过不同的协议来调用。 217
  • 218. 218
  • 219. BPM、EA 和OOAD219
  • 220. OOADOO 支持应用程序分析、设计和开发的完整生命周期 SOAD 应该尽可能多地利用OO 分析技术 将OO 分析成功地应用于SOA 项目 必须一次分析多个系统,用例模型必须继续扮演重要的角色 SOAD 主要是流程,而不是用户驱动的。SOAD 需要BPM 和用例建模活动之间的强链接 OO设计的目标是能够进行快速而有效的设计、开发以及执行灵活且可扩展的应用程序 从OO 的角度看,每件事情都是对象。220
  • 221. 与SO 有关的OO 设计的主要问题 OOAD 粒度级别集中在类级 对于业务服务建模来说,这样的抽象级别过低 诸如继承这样的强关联产生了相关方之间一定程度的紧耦合(因而具有依赖性) SOA 试图通过松耦合来促进灵活性和敏捷性 在SOA 中还没有服务实例的跨平台继承支持和表示法来避免需要处理服务生命周期维护管理问题(如远程垃圾收集)221
  • 222. SOAD 服务定义层次 SOAD服务 可能包括许多协作或编排服务 并没有排除RUP 采用的OO 观点,而是在其上实现了另一个抽象层。 其作用是封装作为正式的跨层接口结构中的软件服务的组件222
  • 223. SOAD的基本要求: 必须正式(至少半正式)地定义流程和表示法 通过选择和组合OOAD、BPM 和EA 必须有结构化的方法来概念化服务: OOAD提供了应用程序层上的类和对象,而BPM 具有事件驱动的流程模型 SOAD 需要将它们结合在一起 方法不再是面向用例的,而是由业务事件和流程驱动的 – 用例建模是在更低的层次上作为第二步进行的 方法包括语法、语义和策略 需要特别的组合、语义代理和运行时发现223
  • 224. 质量因素的考虑 构思良好的服务给业务带来了灵活性和敏捷性 通过松散耦合、封装和信息隐藏使重构更加容易 设计良好的服务是有意义的,并且不只适用于企业应用程序 服务之间的依赖性减到最少,并且是显式声明的 服务抽象是内聚、完整和一致的 例如,在设计服务及其操作签名时应该考虑其CRUD 通常假定服务是无状态的 领域专家无需深奥的专业知识就可以理解服务命名 在SOA 中,所有的服务都遵循相同的设计体系(通过模式和模板连接的)和交互模式;底层架构模式容易识别 服务和服务使用者的开发除了领域知识之外只需要基本的编程语言技能;中间件专业知识只有少数的专业人员才需要224
  • 225. 第五单元:架构设计实践225
  • 226. 软件设计的步骤: 一、静态设计。 二、模块间的通信及耦合设计。 三、动态设计。 四、模块调整。 226
  • 227. 一、静态设计1、按层+高内聚低耦合的原则进行模块划分 1)高内聚低耦合原则(GRASP:高内聚低耦合) 2)按功能分解 3)按业务进行分解 4)以数据转换为中心分解 5)实际运用中的折中 2、划分层次 (架构风格) 1)将模块划入对应的层 2)分层与分区 3)逻辑模块与实体组件的对应关系 227
  • 228. 一、静态设计(续)3、为模块进行职责分配 1)信息专家+控制者 2)隔离关注面(GRASP:保护变量、间接模式) 3)低耦合原则 4)适当采用设计模式 4、用设计模式优化核心结构 1)用策略/桥接模式作为中心骨架(多态模式) 2)用工厂/抽象工厂模式进行组装。(创建者模式) 3)用命令模式处理事务228
  • 229. 一、静态设计(续)5、模块结构的常用形式 1) 容器模块 + 控制者 + 功能模块 + 临时构建的小类。(纯虚构模式) a) 单例模式 b) 命令模式 2) 核心模块的接口设计 a) 外观模式 b) 适配器模式 c) 代理模式 d) 调停者模式 3) 变换型模块结构 4) 事务型模块结构229
  • 230. 二、模块间的通信及耦合设计1、组件式程序设计 通常一个领域的专用资产要应用到不相关的领域是比较困难的,组件式开发的首要工作是领域工程,在这个领域内提取可被复用的系统对象,创建可复用资产,开发复用组件。 面向对象技术的特点是通过对象之间的职责分工和高度协作来完成任务。这样的好 处是代码量较少,系统布局合理,重用程度高,但是当对象的个数大量增加的时 候,对象之间的高度耦合的关系将会使得系统变得复杂,难以理解. 2、通讯机制 观察者模式 本地SDK 轮询230
  • 231. 二、模块间的通信及耦合设计(续)3、解耦 1)针对接口编程;(面向对象原则:接口单一原则) 2)增加间接模块;(间接模式) 3)依赖注入 4、设计数据层 1)数据结构选用的设计 2)数据访问层的设计 231
  • 232. 三、动态设计1、抽象与统一不同的因素 1)根据业务寻找关键因素 2)向复杂的情况靠齐 2、常用的流程抽象手段 1)依赖注入 / 控制反转 / 依赖倒置(面向对象原则) 2)表格法 3)配置文件 3、逻辑控制: 1)控制者模式 2)信息专家模式 4、消息通知机制 1)MVC模式 2)观察者模式 3)责任链模式 4)中介者模式232
  • 233. 四、模块调整1、调整模块等级 1) 适当封装: 2) 把属性提升为类 3) 将类降为属性 4) 将类提升为组件 2、类细化 1) 李氏替换原则 2) 避免脆弱基类等 3、用设计模式优化,在主体框架上进行调整 1)访问者模式 2)装饰模式233
  • 234. 四、模块调整(续)4、编码时构建适当的动态临时类 1) 命令模式 2) 事务处理类型 3) 纯虚构 5、效率的优化 1) 效率与结构的折中 2) 优化效率的3步骤 234
  • 235. 谢谢!235