UML图示表示
- 依赖关系:A------->B B作为A的方法调用参数
- 关联关系:A———————>B B作为A的成员变量使用(暗示两个类在概念上位于相同的级别)
- 聚合关系:A<>—————>B B作为A的成员变量使用(整体/局部关系,暗示着整体在概念上处于比局部更高的一个级别)
- 合成关系:A♦️——-——>B B作为A的成员变量使用(整体要么负责保持局部的存活状态,要么负责将其销毁。局部不可与其他整体共享)
- 继承关系:A———————1> B A作为B的子类
- 实现关系:A-------1> B A实现了接口B
一句话简单描述设计模式六大原则
-
尽可能抽象,逻辑抽取,方便复用,代码的自定义(单一责任原则)
-
依赖于抽象接口协议,而不要依赖于具体的类(依赖倒置原则)
-
子类可以完全替换父类的功能(里氏替换原则)
-
开放的需求通过新增代码实现,新功能可以扩展,修改需求则只需要修改自己的代码就可以了,不会扩散。(开放封闭原则)
-
面向最小接口编程,以免接口臃肿(接口隔离原则)
-
最少知识原则,只和朋友类进行交互,方法内不要使用非朋友类,朋友类指的是:出现在成员变量,方法输入输出参数中的类,和朋友类保持距离,保护自己的隐私,减少类间交互(迪米特法则)
-
合成一句话就是:设计模式总的原则就是让合适的代码放到合适的位置方便复用,减少代码冗余。解耦合就用接口加继承(依赖倒置-开闭原则),具体类接口怎么写(单一责任原则,接口隔离原则),如何写子类(里氏替换原则),类间如何交互(最小知识原则)请看下面你的具体设计模式。
设计模式
-
适配器模式
-
定义
适配器模式是指,将一个类的接口转换为客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
-
结构图
分为类适配器模式和对象适配器模式两种,类适配器模式是通过多继承来实现的,对象适配器模式则很像是代理模式。
-
何时使用
1. 一般是属于事后补救时候使用,接口调用方和被调用方接口都不能修改情况下,为了实现复用该功能一致但接口不同的代码,我们使用适配器 2. 适配器模式还用在封装第三方接口上面,因为我们不希望我们的系统接口随着外部的第三方接口改变而改变,此时我们就是用适配器模式
-
区别于代理模式
相同点:都是将被调用方作为属性来使用 不同点: 1. 适配器中的的代理是已经实现的实体类,不是接口,适配器模式需要适配器继承调用方,然后在调用方接口函数中调用该代理方法 2. 代理模式中的代理在委托中是一个接口,我们不知道代理会具体做什么,但是知道代理的调用时机,我们使用的时候主要是继承代理接口成为代理,然后在代理方法中做我们想做的事情。
-
-
简单工厂模式
-
定义
用一个类来封装子类实例的初始化操作
-
结构图
-
何时使用
1. 重复调用初始化操作的时候,减轻用户的初始化负担
2. 重复调用一些事先可以确定的初始化操作,那么可以放到工厂类中
-
-
策略模式
-
定义
策略模式:定义了算法家族,分别用子类封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到算法的客户。
-
结构图
-
何时使用
1. 封装不同的算法或者是不同的业务规则
2. 减少算法类和算法调用类之间的耦合 -
优点:
1. 方便进行单元测试,每个算法都有自己的接口类,可以通过自己的接口来单独进行测试
-
-
装饰模式
-
定义
装饰模式:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
-
结构图
-
何时使用
1.使用时机:见模式定义 2.实现原理:通过SetComponent 来对对象进行包装,每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中
-
个人理解
有点像链表哦,所有的装饰都可以放入到链表的节点中,然后最后的装饰节点输出会递归的返回上一个节点的输出,这样就给对象增加了不同顺序的功能。
-
-
代理模式
-
定义
代理模式:将自己想做的事情定义一个借口委托给别人代理实现,然后自己拥有这个对象,想让他在什么时候调用什么方法就在什么时候调用什么方法,当然该方法具体做什么还是由代理来决定的。
-
结构图
-
何时使用
1.委托方知道事件的调用时机,但是不知道具体执行的操作
-
-
工厂方法模式(满足开放封闭原则)
-
定义
工厂方法模式:定义一个用于创建对象的接口,让子类来决定实例化哪一个类。工厂方法使一个类的实例化延迟到了子类。
-
结构图
-
简单工厂模式VS工厂方法模式
-简单工厂模式:最大的优点是工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关类,对于客户端来说,去除了与具体产品类名的依赖,但是违反了开放-封闭原则。 -工厂方法模式:客户端需要决定实例化哪一个工厂来实现产品,选择判断的问题还是存在的,也就是说,工厂方法吧简单工厂的内部逻辑判断移到了客户端代码来进行,想要增加产品,本来是修改简单工厂模式内部代码的,现在变成了修改客户端代码,但是满足了开放-封闭原则。
-
-
原型模式
-
定义
原型模式: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
-
结构图
-
理解
-原型模式其实就是从一个对象创建出另外一个可以定制的对象,而且不需要知道任何创建的细节。实现一个clone接口就可以了 -要注意浅拷贝和深拷贝的区别,看我们是要用哪一种,当我们需要修改一次就可以修改对个副本时候,我们使用浅拷贝,当我们希望每一个副本都可以修改为不同的对象属性的时候,我们使用深拷贝。
-
-
模板方法模式
-
定义
模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
-
结构图
-
模板方法模式的特点:
-通过把不变的行为搬移到父类中,去除了子类中的重复代码来体现它的优势 -当不变和可变行为在方法的子类实现中混合在一起的时候,不变行为的在子类重复出现。我们通过模板方法模式把这些行为搬移到一个单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
-
-
外观模式
-
定义
-外观模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层的接口,这个接口是的这一子系统更加容易使用。 -外观模式知道哪些子类负责处理请求,将客户的请求代理给适当的子系统对象
-
结构图
-
何时使用
-在设计初期,应该要有意识的将不同的两个层分离 ,层与层之间建立外观模式 -在开发阶段,子系统因为不断的重构演化而变得越来越复杂,增加外观模式可以提供一个简单的接口,减少他们之间的依赖。 -在维护一个遗留的大型系统时,可能这个系统已经非常难于维护和扩展了,此时可以为新系统开发一个外观类,来提供设计粗糙或高度复杂的遗留代码的比较清晰的接口,让新系统与外观类对象交互,Facade 与遗留代码交互所有复杂的工作。
-
外观模式 VS 适配器模式
-适配器模式:面向接口 -外观模式:面向子系统,符合迪米特原则
-
-
建造者模式
-
定义
建造者模式:将一个复杂对象的构建与它的表示分离,是的同样的构建过程可以创建不同的表示。
-
结构图
-
特点:
-将一个复杂对象的构建与它的表示分离,使得同样的构造过程可以创建不同的表示 -如果我们使用了建造者模式,那么用户只需要指定需要建造的类型就可以得到他们,而具体的建造的过程和细节就不需要知道了。 -Builder :为创建一个Product对象的各个部件指定的抽象接口。 -ConcreteBuilder: 具体的建造者,实现了Builder接口,构造和装配各个部件。 -Product: 具体的产品角色 -Director: 指挥者,用来根据用户的需求创建不同的小人对象
-
何时使用
-主要用来创建一些比较复杂的对象,这些对象内部构建间的建造顺序通常是固定的,但是对象内部的构建通常面临着复杂的变化。 -建造者模式的好处是:使得建造代码和表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。
-
-
观察者模式
-
定义
观察者模式:定义了一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化的时候,会通知所有的观察者对象,使他们能够自动更新自己。
-
结构图
-
何时使用
-将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就需要维护相关对象之间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护,扩展和重用都带来不便。 -当一个对象的改变需要同时改变其他对象的时候,而且不知道有多少对象有待改变 -观察者模式所做的事情是在解耦合,让耦合的双方都依赖于抽象而不是依赖于具体,从而使得各自的变化都不影响另一边的变化
-
委托事件
-观察者模式有个缺点: 通知者要在自己的通知方法中遍历所有的观察者,然后调用这些对象相同的方法,实际情况中可能这些对象想要执行的方法并没有相同的函数名字 -使用委托:委托一种引用方法的类型。一旦为委托分配了方法,那么委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值,委托可以看做是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。 -一个委托可以搭载多个方法,所有的方法将会被依次唤醒。 -可以使得委托对象所搭载的方法并不属于同一个类。 -委托对象所搭载的方法必须具有相同的原形和形式,也就是有相同的参数列表和返回值类型。
-
-
抽象工厂模式
-
定义
抽象工厂模式:提供一个创建一系列或相互依赖对象的即可欧,而无需指定他们具体的类。
-
结构图
-
何时使用
当只有一个产品系列的时候只需要使用工厂方法模式就足够了,但是如果有多个产品系的时候,需要使用抽象工厂模式。
-
优点
- 是易于交换产品系列,由于具体工厂类在一个应用中代表着从产品系,只需要初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,他只需要改变具体的工厂就可以使用不同的产品配置。 - 让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。 - 增加新的产品系列的时候比较方便,只需要增加一个具体的子类Factory 就可以了
-
缺点
- 当增加新的功能(产品)的时候,我们需要修改Factory 接口以及具体的Factory实现来满足我们的要求,不满足封闭性原则。
-
改进
-使用简单工厂模式可以有效改善增加新的产品的问题,这时我们只需要添加产品,然后在简单工厂里面添加case 语句就可以了。 -再进一步,使用反射可以去除掉case语句,只需要修改对应的类名字符串就可以了。此时的字符串如果是定义在工厂内部的,那么可以使用配置文件来配置,然后让该字段读取该配置文件来解决;当然也可以放在参数里面,由调用方决定使用哪一个,但是这样可能会更改很多次哦。
-
-
状态模式
-
定义
状态模式:当一个对象的内在状态发生了改变时,允许改变其行为,这个对象看起来像是改变了其类。
-
结构图
-
何时使用
-状态模式:主要解决的是当控制一个对象状态转换条件的条件表达式过于复杂时的情况。把状态的判条件转移到表示不同状态的一些列类当中,可以把复杂的判断逻辑简化。
-
优点(类似于活字印刷术的出现)
- 将于特定状态相关的行为局部化,并且将不同的状态的行为分割开来 - 将特定的状态相关的行为放到一个对象中,由于所有与状态相关的代码都存在于某一个ConcereateState 中,所以通过定义新的子类可以很容易地增加新的状态和转换。 -消除庞大的条件分支语句,状态模式通过将各种状态转移逻辑分布到state的子类中,来减少相互间的依赖。 好比把整个版面又改成一个一个活字了
-
-
备忘录模式
-
定义
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
-
结构图
- Originator(发起人): 负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录来恢复内部的状态。Originator 可根据需求决定Memoto 存储Originator 的哪些内部状态 - Memeto(备忘录):负责存储Originator 对象的内部状态,并可防止Originator 以外的其他对象访问备忘录Memento. 备忘录有两个接口,Caretaker 只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator 可以看到一个宽接口,允许它访问返回到之前状态所需的所有数据。 - CareTaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。
-
何时使用及优点
- 把要保存的细节全部封装在Memento 中,客户端在保存和恢复的过程中不需要了解这些细节了
- Memonto 模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性知识众多属性中的一小部分。
-
缺点
角色状态信息要完整的保存在备忘录对象中,如果数据太多,会很占内存。
-