部分预览:
-
面向对象设计与复用
- 定义:面向对象设计的任务是对面向对象分析的结果作进一步的规范化整理,以便能够被面向对象编程直接接受。
- 层次:
- 框架级设计-框架模式
- 类设计-软件设计模式
- 代码设计-微模式
- 类的设计
- 包括:类的组织与表示、行为的组织与表示、属性的组织与表示
- 难点:变化的存在——职责的变化(接口、功能的变化)、实现的变化(数据表示、行为的变化)
- 如何适应变化:修改或拓展既有代码
- 复用:关系模型是复用的基础
-
类间关系(程度由弱到强)
- 依赖:两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务。(虚线箭头)
- 关联(knows-a):一个对象的实例与另一个对象的一些特定实例存在固定的对应关系。(实线箭头)
与依赖关系的区别:比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。
- 聚合(has-a):B是A的组成部分。(空心菱形)
- 与关联关系的关系:聚合关系是关联关系的特例。关联关系中两个类是处于相同的层次,而聚合关系中两个类是处于不平等的层次,一个表示整体,一个表示部分。
- 特点:整体与部分之间是可分离的,可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。
- 组合(contains-a):强聚合,整体与部分是不可分的,整体类负责部分类的生存与消亡。(实心菱形)
与聚合关系的区别:部分不能脱离整体存在,整体生命周期结束就意味着部分生命周期结束。
- 泛化:是一种一般与特殊、一般与具体之间关系的描述,具体描述建立在一般描述的基础之上,并对其进行了扩展。通过继承实现。
- 实现:是一种类与接口的关系,表示类是接口所有特征和行为的实现。
泛化和实现的区别:子类是否继承了父类的实现,如有继承则关系为泛化,反之为实现。
-
面向对象设计原则
包括:类的设计原则和包的设计原则。
类的设计原则包括:
关于设计目标:开闭原则、里氏代换原则、迪米特原则
关于设计方法:单一职责原则、接口分隔原则、依赖倒置原则、组合/聚合复用原则
- 开闭原则(OCP):软件实体(模块,类,方法等)应该对扩展开放,对修改关闭
- 是面向对象的可复用设计的基石
- 系统设计需要遵循开闭原则的原因:
- 稳定性。开闭原则要求扩展功能不修改原来的代码,这可以让软件系统在变化中保持稳定。
- 扩展性。开闭原则要求对扩展开放,通过扩展提供新的或改变原有的功能,让软件系统具有灵活的可扩展性。
遵循开闭原则的系统设计,可以让软件系统可复用,并且易于维护。
-
- 实现方法:面向接口的程序设计。把这些不变的部分加以抽象成不变的接口,这些不变的接口可以应对未来的扩展。根据接口的最小功能设计原则,原有的接口要么可以应对未来的扩展;不足的部分可以通过定义新的接口来实现;模块之间的调用通过抽象接口进行,这样即使实现层发生变化,也无需修改调用方的代码。
- 里氏替换原则(LSP):所有引用基类的地方都必须能透明地使用其派生类对象。
- 两个条件
- 不应该在代码中出现 if/else 之类对派生类类型进行判断的条件
- 派生类对象应当可以替换基类对象并出现在基类对象能够出现的任何地方
- 里氏替换原则 LSP 是使代码符合开闭原则的一个重要保证。
- LSP 体现了:
- 类的继承原则:如果一个派生类对象可能会在替换基类对象的地方出现运行错误,则该派生类不应该从该基类继承。
- 动作正确性保证:从另一个侧面上保证了符合 LSP 设计原则的类的扩展不会给已有的系统引入新的错误。
- 两个条件
- 迪米特原则(LoD,最少知道原则):只和直接的朋友通信
- 理解:
- 一个软件实体应当尽可能少地与其他软件实体发生相互作用。
- 每一个软件实体对其他软件实体都只有最少的知识,而且局限于那些与本软件实体密切相关的软件实体。
- 例子:showInfo不应该在类中,而应该在外部调用中,类中只应该有getInfo()。因为cout是在iostream头文件中,不应该让类对库有更多依赖。
- 对应的设计模式:外观模式、中介者模式
- 理解:
- 单一职责原则(SRP):让一个类有且仅有一个职责。
- 理解:如果一个类存在多个改变的原因,那么这个类就存在多个职责。
- 原因:如果一个类存在多个改变的原因,而变化将影响到该类不同职责的使用者
- 如果一个职责使用了外部类库,则使用另外一个职责的用户也不得不包含这个未被使用的外部类库。
- 某个用户由于某个原因需要修改其中一个职责,另外一个职责的用户也将受到影响,不得不重新编译和配置。
这违反了设计的开闭原则(对修改关闭)。
- 接口分隔原则(ISP):不能强迫用户去依赖那些他们不使用的接口。
- 接口的设计原则:最小。使用多个专门的接口代替单一的胖接口。
- 接口的依赖原则:如果一个接口 a 继承接口 b,则接口 a 也不应该包含用户不使用的方法。反之,则说明接口 a 被 b 给污染了,应该重新设计它们的关系。
- 与SRP的关系
- 共同点:都是为了高内聚、低耦合,体现了封装的思想。表现都是将接口约束到最小功能。
- 区别:单一职责原则针对的是模块、类、接口的设计,接口隔离原则更侧重于接口的设计。单一职责原则是从软件实体本身的职责/功能是否单一来考虑,接口隔离原则主要是从用户的角度来考虑接口约束问题。在系统外通过文 档约束“不使用的方法不要访问”,按照单一职责原则是允许的,按照接口隔离原则是不允许的。
- 依赖倒置原则(DIP):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
- 组合/聚合复用原则(CAUR):尽量使用组合/聚合而非继承来达到复用目的
- Coad 条件全部满足时才应使用继承关系
- 派生类是基类的一个特殊种类,而不是基类的一个角色。
- 永远不会出现需要将派生类换成另外一个类的派生类的情况。
- 派生类具有扩展基类的责任,而不是具有置换或注销掉基类的责任。
- 分类学角度上有意义。
- 组合/聚合复用的优缺点
- 优点:新对象存取成员对象的唯一方法是通过成员对象的接口,是黑箱复用,支持封装性。依赖性比较小,每个新的类可以聚焦于一个任务上。这种复用可以在运行时间内动态进行,可以应用到几乎任何环境中去。
- 缺点:需要管理较多对象
- 继承复用的优缺点
- 优点:新的实现较为容易,因为基类的大部分功能可以通过继承的关系自动进入派生类。修改和扩展继承而来的实现较为容易。
- 缺点:破坏封装性,因为继承将基类细节暴露给派生类。又称“白箱” 复用。如果基类发生改变,那么派生类的实现也不得不改变。从基类继承而来的实现是静态的,不能在运行时改变,不够灵活。
- Coad 条件全部满足时才应使用继承关系
-
设计模式概述
- 模式
- 要素:Context,Theme/Problem,Solution
- 定义:在特定环境中解决问题的一种方案。(Alexander给出了关于模式的经典定义:每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的解决方案,无需再重复相同的工作)
- 软件模式
- 软件模式并非仅限于设计模式,还包括架构模式、分析模式和过程模式等,实际上,在软件生存期的每一个阶段都存在着一些被认同的模式。
- 要素:问题描述、前提条件、解法、效果
- 大三律(Rule of Three):只有经过三个以上不同类型的系统的校验,一个解决方案才能从候选模式升格为模式。
- 设计模式
- GoF:1994年归纳发表了23种使用频率较高的设计模式。1995年,出版了《设计模式:可复用面向对象软件的基础》。
- 要素:模式名称、问题、解决方案、效果
- 分类
- 目的:创建型模式——创建对象。结构型模式——处理类或对象的组合。行为型模式——描述对类或对象怎样交互和怎样分配职责。
- 范围:类模式——处理类和子类之间的关系,这些关系通过继承建立,在编译时就被确定下来,静态。对象模式——处理对象间的关系,这些关系在运行时刻变化,动态。
|
范围\目的 |
创建型模式 |
结构型模式 |
行为型模式 |
|
类模式 |
工厂方法模式 |
(类)适配器模式 |
解释器模式 模板方法模式 |
|
对象模式 |
抽象工厂模式 建造者模式 原型模式 单例模式 |
(对象)适配器模式 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式 |
职责链模式 命令模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 策略模式 访问者模式 |
- 设计模式的优点
- 有助于初学者更深入地理解面向对象思想
- 提高软件系统的开发效率和软件质量,且节约设计成本
- 使得设计方案更加灵活,易于修改
- 使人们可以更加简单方便地复用成功的设计
- 方便开发人员沟通交流
-
三种设计模式概述
- 创建型模式
- 定义:将创建对象的过程进行了抽象和封装,分离了对象创建与使用
- 特点
- 客户端不知道对象的具体类
- 隐藏了对象是如何被创建和组织的
- 结构型模式
如何将类或者对象结合在一起形成更大的结构
- 行为型模式
对在不同的对象之间划分责任和算法的抽象化
后续见资源
6183

被折叠的 条评论
为什么被折叠?



