这是我参与「第四届青训营 」笔记创作活动的的第2天
一、本堂课重点内容
1,七个设计原则
2,21种设计模式
二、详细知识介绍
| 设计原则名称 | 设计原则简介 | 重要性 |
|---|---|---|
| 单一职责原则(Single Responsibility Principle, SRP) | 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。 | 高内聚、低耦合 易于被复用 |
| 开闭原则(Open-Closed Principle, OCP) | 软件实体对扩展是开放的,但对修改是关闭的,即在不修改一个软件实体的基础上去扩展其功能 | 抽象化是开闭原则的关键。 面向对象设计的目标 |
| 里氏代换原则(Liskov Substitution Principle, LSP) | 在软件系统中,一个可以使用基类对象的地方必然可以使用一个子类对象 | 符合开闭原则 是依赖倒转原则的基础,依赖倒转原则是里氏代换原则的重要补充。 |
| 依赖倒转原则(Dependency Inversion Principle, DIP) | 要针对抽象层编程,而不要针对具体类编程 定义:高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象即是要针对接口编程,而不是针对实现编程 | 面向对象设计的手段 以抽象方式耦合是依赖倒转原则的关键 |
| 接口隔离原则(Interface Segregation Principle, ISP) | 使用多个专门的接口来取代一个统一的接口 定义“客户端不应该依赖那些它不需要的接口。(在该定义中的接口指的是所定义的方法。) | 满足单一职责原则 |
| 合成复用原则(Composite Reuse Principle, CRP) | 在系统中应该尽量多使用组合和聚合关联关系,尽量少使用甚至不使用继承关系 | 继承不灵活,破坏封装,黑箱 |
| 迪米特法则(Law of Demeter, LoD) | 一个软件实体对其他实体的引用越少越好,或者说如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,而是通过引入一个第三者发生间接交互 指一个软件实体应当尽可能少的与其他实体发生相互作用。 | 与依赖倒转原则互补使用 |
软件复用优点:提高软件的开发效率,提高软件质量,节约开发成本,恰当的复用还可以改善系统的可维护性。
面向对象设计复用的目标在于实现支持可维护性的复用
面向对象设计的重要原则是创建抽象化,并且从抽象化导出具体化,具体化给出不同的实现。继承关系就是一种从抽象化到具体化的导出。
实现开闭原则的关键是抽象化,并且从抽象化导出具体化实现,如果说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要手段。
里氏代换原则的几层含义:
子类必须完全实现父类的方法 子类可以有自己的个性 覆盖或实现父类的方法时输入参数可以被放大 覆盖或实现父类的方法时输出结果可以被缩小
里氏代换的好处:
第一、保证系统或子系统有良好的扩展性。只有子类能够完全替换父类,才能保证系统或子系统在运行期内识别子类就可以了,因而使得系统或子系统有了良好的扩展性。
第二、实现运行期内绑定,即保证了面向对象多态性的顺利进行。这节省了大量的代码重复或冗余。避免了类似instanceof这样的语句,或者getClass()这样的语句,这些语句是面向对象所忌讳的。
第三、有利于实现契约式编程。契约式编程有利于系统的分析和设计,指我们在分析和设计的时候,定义好系统的接口,然后再编码的时候实现这些接口即可。在父类里定义好子类需要实现的功能,而子类只要实现这些功能即可。
依赖倒转:
依赖倒转原则的优点:
采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减少并行开发引起的风险,提高代码的可读性和可维护性。
next 以抽象方式耦合是依赖倒转原则的关键
接口隔离原则
根据接口隔离原则,一个类对另外一个类的依赖性应当是建立在最小的接口上.
合成复用:
继承复用:实现简单,易于扩展。破坏系统的封装性; 从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;只能在有限的环境中使用。(“白箱”复用 ) 组合/聚合复用:耦合度相对较低, 选择性地调用成员对象的操作;可以在运行时动态进行。(“黑箱”复用 )
里氏代换原则
遵循严格的继承 优点:信息隐藏 缺点:通信效率低,不容易协调
创建型设计模式
对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的
结构性设计模式
描述如何将类或者对象结合在一起形成更大的结构,
大部分结构型模式都是对象结构型模式。
行为型设计模式
简单讲行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。
解模职中迭备观状策访命
是对在不同的对象之间划分责任和算法的抽象化,不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。
在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
类或对象之间的交互
模板模式
定义:
定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法是一种类行为型模式
基于继承的代码复用基本技术,父类定义多个方法相同代码放父类,声明一些抽象方法,不同方式的实现放子类
模板方法模式中,方法可以分为模板方法和基本方法,其中基本方法又可以分为抽象方法、具体方法和钩子方法
public class TemplateMethodPattern {
public static void main(String[] args) {
AbstractClass tm = new ConcreteClass();
tm.TemplateMethod();
}
}
//抽象类
abstract class AbstractClass {
//模板方法
public void TemplateMethod() {
SpecificMethod();
abstractMethod1();
abstractMethod2();
}
//具体方法
public void SpecificMethod() {
System.out.println("抽象类中的具体方法被调用...");
}
//抽象方法1
public abstract void abstractMethod1();
//抽象方法2
public abstract void abstractMethod2();
}
//具体子类
class ConcreteClass extends AbstractClass {
public void abstractMethod1() {
System.out.println("抽象方法1的实现被调用...");
}
public void abstractMethod2() {
System.out.println("抽象方法2的实现被调用...");
}
}
求开发抽象类和开发具体子类的设计师之间进行协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。实现这些具体逻辑步骤的方法称为基本方法(Primitive Method),
实现子类对父类行动的反向控制
优点:
1,父类定义算法,子类实现细节处理
2,于在子类定义详细的处理算法时不会改变算法的结构,实现了代码的复用
3,实现子类对父类的反向控制,符合开闭原则
缺点
每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。
适用环境
1,将可变行为留给子类
2,公共方法交给父类
3,对复杂算法的分割
4,控制子类的扩展
迭代器模式
首先确定聚合对象是个LIST或set!!!所以要定义数组
迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过而哪些没有。
定义:
提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式
分析:
聚合对象主要拥有两个职责:一是存储内部数据;二是遍历内部数据。 存储数据是聚合对象最基本的职责。 将遍历聚合对象中数据的行为提取出来,封装到一个迭代器中,通过专门的迭代器来遍历聚合对象的内部数据,这就是迭代器模式的本质。迭代器模式是“单一职责原则”的完美体现。
就是只存储数据了,创建一个聚合器去做遍历的事情
,聚合对象类只需在那里创建一个迭代器即可
在迭代器模式中应用了工厂方法模式,聚合类充当工厂类,而迭代器充当产品类,由于定义了抽象层,系统的扩展性很好,在客户端可以针对抽象聚合类和抽象迭代器进行编程。
优点:
1,支持以不同方式遍历聚合对象
2,开闭原则
3,简化了聚合类
4,同一个聚合可以有很多遍历
迭代器模式:
产品类也就是聚合类要定义List的模式:是抽象类的那个
聚合实现类要createIterator返回值直接一个迭代器对象
聚合类指向迭代器类
访问者模式
定义
表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
访问者模式包含如下角色: Vistor: 抽象访问者 ConcreteVisitor: 具体访问者 Element: 抽象元素 ConcreteElement: 具体元素 ObjectStructure: 对象结构
访问者:visit(ConcreteElementA a)
元素 accept(Visitor visitor){
visitor.visit(this)
优点
1,新增访问者容易,可以在不修改对象结构中元素的情况下位对象结构中的元素添加新功能
2,将有关元素对象的访问行为集中到一个访问者对象中
3,跨过类的等级结构访问属于不同的登记结构的元素类
缺点
1,新增元素类很困难,违背开闭原则了
2,破坏封装 访问者对象要访问元素类,元素类必须暴漏自己内部操作和内部状态
观察者模式:
定义:
定义一对多的依赖关系,当每一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新
因为是一对多的关系,所以subject具体类要定义List数组为了Observer类
优点
1,实现表示层与数据逻辑层的分离
2,观察者模式在观察目标和观察者之间建立一个抽象的耦合。 (具体类和抽象类之间有依赖关系)
3,支持广播通信
4,符合开闭原则
缺点
1,若一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2,如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
3,观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
策略模式
定义
将算法单独包装,就变成一个策略
定义一系列算法,将每一个算法封装起来,并让定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式
优点
1,支持开闭原则 ,户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
2,提供了管理相关的算法族的办法
3,替换继承关系的办法
4,避免使用多重条件转移语句
缺点
1,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 2,策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数
命令模式
要发请求但不知道请求的接收者是谁,也不知道被请求的操作是哪个,使得请求发送者与请求接收者消除彼此之间的耦合。发送者与接收者完全解耦
定义:
将一个请求封装成一个对象,从而使我们可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
本质:对命令进行封装,将发出命令的责任和执行命令的责任分割开。
请求方不知道reciever是谁
优点
降低耦合度
新的命令容易加到系统中
缺点:
导致某些系统有过多的具体命令类
备忘录模式
优点:
1,提供了一种状态恢复的实现机制,
2,实现了信息的封装(只有原发器才能调用恢复)
缺点
资源消耗大
适配器模式
有类适配器模式 对象适配器模式
优点
适配器模式的主要优点是将目标类和适配者类解耦,增加了类的透明性和复用性,同时系统的灵活性和扩展性都非常好,更换适配器或者增加新的适配器都非常方便,符合“开闭原则”;
缺点
类适配器模式的缺点是适配器类在很多编程语言中不能同时适配多个适配者类(几个还是可以的),对象适配器模式的缺点是很难置换适配者类的方法。
适用情况
适配器模式适用情况包括:系统需要使用现有的类,而这些类的接口不符合系统的需要;
想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类一起工作。
桥接模式 注意和组合模式有点像哦
桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
定义:
将抽象部分与它的实现部分分离,使它们都可以独立地变化
分离就是脱耦
就是本来color和pen是接口的 但给弄成聚合了
优点:
1,分离抽象接口及其实现部分。
2,分离抽象接口及其实现部分。
3,实现细节对客户透明,可以对用户隐藏实现细节
4,降低耦合性
缺点
1,增加系统的理解与设计难度
2,其使用范围具有一定的局限性。
适用范围♥
抽象化的角色和实现化的角色
一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
组合模式:
定义
组合模式(Composite Pattern):组合多个对象形成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性
代理模式
定义:
:给某一个对象提供一个代理,并由代理对象控制对原对象的引用
客户通过这个代理调用对象
装饰模式
定义
动态地给一个对象增加一些额外的职责(Responsibility)
汇总
模板方法模式:符合开闭原则,单一职责原则
迭代器模式:满足开闭原则,单一职责原则
访问者模式 倾斜的开闭原则,对象结构有一个list:ArrayList=new ArrayList()
观察者模式:开闭原则
策略模式:开闭原则
适配器模式:开闭原则