Head First设计模式学习总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huangyaa729/article/details/88120773

1、策略模式:
定义了算法族(行为组),分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的用户;

1)对于一个复杂的对象,本身有不变的行为和变化的行为,为了进行合适的抽象,需要把不变的行为和变化的行为进行区分,然后分别包装,方便后续的扩展,当需要实现具体的对象时,再根据实际的需要实现自己的行为进行组合,达到自己的目的。
2)在组合实现时,要动态的设定行为(通过set方法在需要时动态的指定),而尽量避免创建时静态的绑定(原文:不应该对具体的实现编程,即在创建对象实例时直接指定行为的实现类;)

书中的此例的最终类图

在这里插入图片描述
其他应用示例参考:https://www.jianshu.com/p/7b7de81cdfbe

2、观察者模式:

1)观察者模式定义了对象之间一对多的关系
2)主题(可观察者,即内容发布者)用一个共同的接口来更新观察者
3)观察者与发布者之前用松耦合的方式结合,发布者不知道观察者的实现细节,只知道观察者实现的接口;
4)使用此模式时,你可从被观察者(发布者)处push(发布者主动通知)或者pull数据(然而,push的方式被认为更正确)

下图为书中给的类图
在这里插入图片描述
3、装饰者模式:
1)在不修改任何底层代码的情况下,给对象增加新的功能;适用于开发----关闭原则(对扩展开放,对修改关闭);
2)装饰者和被装饰者(组件)必须继承共同的超类(抽象类或者接口),主要是为了达到“类型匹配”,而不是利用继承获得超类的“行为”;
3)装饰者类定义了一个组件对象属性,因此只能装饰一个具体实现的组件(被装饰者类),会导致设计中出现许多小对象,如果过度使用,会让程序变的复杂。

下图为装饰者模式的类图
在这里插入图片描述
4、工厂模式(工厂方法、简单工厂、抽象工厂)
1)简单工厂:简单工厂方式并不是一种设计模式,比较像是一种编程习惯,可以将客户程序从具体实现类中解耦;
在这里插入图片描述
2)工厂方法:在抽象类中定义工厂方法,使用继承的方式,把对象的创建委托给子类,子类实现工厂方法来创建对象,让类把实例化推迟到子类;(每个类型和风味的pizza都需要一个实现,商店根据客户选择的风味和类型来创建pizza,但每个商店对于同一种类型的pizza也可定义不同的实现(这是与工厂模式的主要区别,工厂模式每种类型的pizza实现相同,风味根据采用的原料工厂来决定))
在这里插入图片描述
3)抽象工厂:提供一个接口,用于创建相关或依赖对象的一组属性,而不需要指定具体类;主要使用对象组合的方式,对象的创建被实现在工厂接口所暴露出来的方法中。(每种pizza的制作类型相同,根据不同风味可以创建出不同的pizza,因此采用风味工厂模式,此种风味的产品都可以采用一个工厂来生成原料)
在这里插入图片描述
所有的工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合;具体使用哪种方式要根据场景而定。
https://www.cnblogs.com/HectorHou/p/5987409.html(具体类的参考文章)

5、单例模式:
可参照下面链接的文章熟悉其各种写法
https://blog.csdn.net/huangyaa729/article/details/88646213

6、命令模式
当需要将发出请求的对象和执行请求的对象解耦时,使用命令模式

  1. 命令模式将发出请求的对象和执行请求的对象解耦;
  2. 在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接受者和一个或者一组动作;
  3. 调用者通过调用命令对象的excute()发出请求,这会使得接收者的动作被调用;
  4. 调用者可以接受命令作为参数,甚至在运行的时候动态的进行;

实际应用:日志和事物系统
下图为对应的类图
在这里插入图片描述

7、适配器和外观模式

1)定义
适配器模式:将一个类的接口转换成客户期望的另一个接口;适配器让原本不兼容的类可以合作无间。
适配器模式有两种形式:对象适配器和类适配器;类适配器需要用到多重继承,对象适配器使用组合的方式,结构上更加灵活;

对象适配器模式类结构图
在这里插入图片描述
类适配器模式结构图
在这里插入图片描述
外观模式:提供了一个统一的接口,用来访问子系统中的一群接口;外观定义了一个高层接口,让子系统更容易使用。
外观模式类结构图
在这里插入图片描述
2)使用原则:
(1)当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器;适配器改变接口以符合客户的期望;
(2)当需要简化并统一一个很大的接口或者一群复杂的接口是,使用外观;外观将客户从一个复杂的子系统中解耦;

总结:适配器模式将一个对象包装起来以改变其接口;装饰器模式将一个对象包装起来以增加新的行为和责任;而外观模式将一群对象包装起来以简化其接口

8、模板方法模式
1) 定义:在一个方法中定义一个算法的框架(总体实现逻辑),而将一些步骤延迟到子类中实现。
2)特点:
(1)模板方法使得子类可以在不改变算法结构的情况下重新定义算法中的某些步骤;
(2)模板方法的抽象类可以定义具体方法、抽象方法和钩子,抽象方法由子类实现;钩子方法在抽象类中不做事,或者只做默认的事情,子类可以选择要不要覆盖它;
(3)为了防止子类改变模板方法中的算法(实现逻辑),可以将模板方法声明为final。
3)区别:
(1)策略模式和模板方法模式都是封装算法(行为),一个用组合把对象需要用到的行为聚集在一起(策略),一个用继承,在子类中实现整体逻辑中的部分不同行为;模板方法模式更强调整体算法(逻辑)的一致性。
(2)工厂方法是模板方法的一种特殊版本。

模式的类图如下所示:
在这里插入图片描述

9、迭代器模式和组合模式

1)定义:
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示;
组合模式:允许你将对象组成树形结构来表现“整体/部分”的层次结构;组合能让客户以一致的方式处理个别对象和组合对象。
2)特点:
(1)迭代器允许访问聚合的元素,而不需要暴露它的内部结构;
(2)迭代器将遍历聚合的工作封装进一个对象中;迭代器提供一个通用的接口让我们遍历聚合项。
(3)组合模式允许客户对个别对象以及组合对象一视同仁;
(4)组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点,但都是继承同一个接口,内部的实现对客户透明。

迭代器模式类图
在这里插入图片描述
组合模式类图
在这里插入图片描述
10、状态模式

1)定义:
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

这个模式将状态封装成独立的类,并将动作委托到代表当前状态的对象,这就是说行为会随着内部状态而改变。 “看起来好像修改了它的类”是什么意思呢?从客户的视角来看:如果说你使用的对象能够完全改变它的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然而,实际上,你知道我们是在使用组合通过简单引用不同的状态对象来造成类改变的假象。

2)我们仔细体会一下定义当中的要点
(1)有一个对象,它是有状态的。
(2)这个对象在状态不同的时候,行为不一样。
(3)这些状态是可以切换的,而非毫无关系。
(4)客户不会和状态进行交互,全盘了解状态是 context的工作
(5)在状态模式中,每个状态通过持有Context的引用,来实现状态转移
(6)使用状态模式总是会增加设计中类的数目,这是为了要获得程序可扩展性,弹性的代价,如果你的代码不是一次性的,后期可能会不断加入不同的状态,那么状态模式的设计是绝对值得的。【同时也是一个缺点】
(7)状态类可以被多个context实例共享

3)策略模式和状态模式的差别:
在于它们的”意图“不同:
状态模式帮助对象管理状态,我们将一群行为封装早状态对象中,context的行为随时可委托到那些状态中的一个.随着时间的流逝,当前状态在状态对象集合中游走改变,以反映context内部状态,因此,context的行为也会跟着改变。当要添加新的状态时,不需要修改原来代码添加新的状态类即可。 而策略模式允许Client选择不同的行为。通过封装一组相关算法,为Client提供运行时的灵活性。Client可以在运行时,选择任一算法,而不改变使用算法的Context。一些流行的策略模式的例子是写那些使用算法的代码,例如加密算法、压缩算法、排序算法。客户通常主动指定context所要组合的策略对象是哪一个.

总结:最根本的差异在于策略模式是在求解同一个问题的多种解法,这些不同解法之间毫无关联;状态模式则不同,状态模式要求各个状态之间有所关联,以便实现状态转移,这些状态转移对客户是不可见的,是既定好的方案

状态转换图
在这里插入图片描述
对应的状态模式类图
在这里插入图片描述
11、代理模式

1)定义
为某个对象提供一个替身(代理)以控制对这个对象的访问。
以实现的方式不同可以分为3类:静态代理(远程代理、虚拟代理)、动态代理(必须指定代理接口)、CGLIB代理(不需要指定接口)
2)特点
代理模式最大的特点是调用者无法直接访问被调用者,中间隔了一个代理对象,相当于一个类似中介的对象。利用这个特点可以做到如下功能:
1.限制调用者,只给调用者有限的访问权限,这也是常说的访问控制。
2.通过代理对象实现跨进程调用,即远程代理。
3.当创建对象的开销很大时,我们往往会创建一个虚拟代理,虚拟代理可以处理一些简单的请求,但有些东西只有真实对象才能进行。但是由于真实对象创建非常耗资源,只有当必要时刻才会创建真实对象,以节省资源。真实对象创建前和创建中,均由代理类充当真实对象,即虚拟代理;

基本代理模式的类图
在这里插入图片描述
12、桥接模式
1)定义
桥接模式(Bridge)是一种结构型设计模式。Bridge模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。

在这里插入图片描述
2)桥接模式的优点

(1)实现了抽象和实现部分的分离

桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。

(2)更好的可扩展性

由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。

(3)可动态的切换实现

由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。

(4)实现细节对客户端透明,可以对用户隐藏实现细节。

3)桥接模式的缺点

(1)桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。

(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。

参考博文(https://www.cnblogs.com/lixiuyu/p/5923160.html)

13、生成器模式

1)定义
生成器模式的核心是当构建生成一个对象的时候,需要包含多个步骤,虽然每个步骤具体的实现不同,但是都遵循一定的流程与规则 ;
2)优点
生成器模式将对象的构造过程封装在具体生成器中,用户使用不同的具体生成器就可以得到该对象的不同表示。
生成器模式将对象的构造过程从创建对象的类中分离出来,使用户无需了解该对象的具体组件。
可以更加精细有效地控制对象的构造过程。生成器将对象的构造过程分解成若干步骤,这就使程序可以更加精细,有效地控制整个对象的构造。
生成器模式将对象的构造过程与创建该对象类解耦,使对象的创建更加灵活有弹性。
当增加新的具体生成器时,不必修改指挥者的代码,即该模式满足开-闭原则。
3)结构

  • Builder:生成器接口,定义创建一个Product对象所需要的各个部件的操作。
  • ConcreteBuilder:具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。
  • Director:指导者,也被称导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象。
  • Product:产品,表示被生成器构建的复杂对象,包含多个部件。
    在这里插入图片描述
    参考文章:https://www.jianshu.com/p/f4248525e2d1

14、责任链模式
1)定义
将多个对象连成一条链,沿着这条链传递请求,直到有一个对象处理它为止,使得多个对象都有机会处理该请求。

在这里插入图片描述

public abstract class Handler {
      public Handler successor = null;
      public abstract boolean canHandle();
      public abstract void handle();

     public void handleRequest() {// handleRequest方法处理示例
         if(canHandle()) {
            handle();
         } else {
             getSuccessor().handleRequest();
         }
     }
 
     public Handler getSuccessor() {
         if(successor==null) {
             successor = new EmptyHandler();//没有设置下一个,则用默认的处理方式
         }
        return successor;
     } 
     public void setSuccessor(Handler successor) {
         this.successor = successor;
     }
 }

2)纯责任链与不纯责任链

(1)纯责任链:
1 当handler能处理请求时,停止调用下一个handler。当handler不能处理请求时,继续调用下一个handler。只能在两个行为中选择一个,一是承担责任,二是把责任推给下家。

2 一个请求必须被某一个处理者对象接收。

例如:工厂产品的质量检查流水线,如果出现问题,就直接将产品拿出来。如果通过检查,则传递给下一个检查员。

(2)不纯责任链:

1 承担一部分责任又把责任传到下一个处理者(好比工厂的流水线,每处理完一道工序,交给下一个人处理)。

2 一个请求可以不被任何处理者接收。

例如:工厂产品的生产流水线,每个人都会处理一部分,然后交给下一个人

优点:
1 责任链模式最大的好处:可以根据需求组织对应的责任链处理请求,调用某个处理者即可,不用知道它内部的实现(它可以自己处理,也可以委托其它处理者处理)。

问题:
1 为什么不将处理器组成一个List,然后按顺序处理请求?
这样请求可能被处理多次,在某些业务场景是不合适的(比如付款单发给多个付款者,则会发生多次付款)。这些场景处理者处理完毕后,不需要下一个处理者接着处理,这样就不能用列表,而是通过责任链处理,当不需要往下传递时,马上终止处理。
2 责任链模式最可能在什么场景下使用?
当业务逻辑中包含多个if、else分支,代码看上去很糟糕时,可以考虑使用责任链模式将条件判断逻辑分散到多个处理者对象中。
参考文档:https://www.cnblogs.com/fanyang219/p/6432815.html

15、蝇量模式
1)定义
主要用于减少创建对象的数量,以减少内存占用和提高性能。
这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。通过共享的方式高效的支持大量细粒度的对象。

接触的不多,不做详细的解释与记录;
参考文献:https://www.cnblogs.com/pony1223/p/7554686.html

剩下的解释器、中介者、备忘录、原型(https://www.cnblogs.com/chenssy/p/3313339.html)、访问者(https://blog.csdn.net/u012124438/article/details/70537203)等等模式实际应用的场景较少,不再做总结。

猜你喜欢

转载自blog.csdn.net/huangyaa729/article/details/88120773