设计模式笔记

来源:互联网 发布:b2c网络建站 编辑:程序博客网 时间:2024/05/29 17:47

创建型模式

工场模式:

简单工场,简单工场就是把实现隐藏起来,有一个接口A,以及它的实现AimplX,AimplY,普通情况下要得到一个A的操作,就是A a=new Aimpl();,简单工场,则是将对A的new实现放到工场中来做,新建一个工场类B,B,B中有一个方法用来产生A的实例,普通工场则是接收一个值用于判断要生产哪种类型的A,或者直接写多个方法,不同的方法返回不同的A实例,可以做成对象方法也可以做成类方法,如果怕工场被过多实例化消耗资源可以考虑用类方法来实现。但是如果以后A的实现又多了一种,就得去修改工场类B来增加对新实现的支持,这就违背了不应修改的原则,这时可以考虑用抽象工场,抽象工场提供返回A实例的方法,由子类工场去实现要返回的类实现实例,如果要增加新的实现实例,只需要增加一个工场实现即刻。抽象工场也可以做成类组合的抽象工场也就是某一类型的抽象工场。


单例模式:

对于某种数据,任何时刻只希望只有一个入口来交互的场景,如读取配置文件。新建一个类A,将A的构造函数私有化,防止被new,向外提供一个静态方法来获取实例。优先采用双重校验锁机制,volatile修饰单例,synchronized(A.class){new A}


建造者模式:

适用于内部构造类比较复杂,具有多个参数,多种构造方法等场景;使用一个内部Build类来完成对象的创建。


原型模式:

适用于需要复用的对象,原型类实现Cloneable接口


结构型模式


适配器模式:

类适配器,

有一个接口A,等待实现,有一个类B,具有类似A接口的功能,现在为了达到不想去写一个A的实现类而是使用现有的B类来做为A接口的实现类,这是就可以使用类适配器了,

新建一个适配器类C,C继承了B类并实现了A接口,这时C就拥有了A和B的功能,也就可以这样写:A a=new C();   ,当然如果接口A和B的方法 都相同,是最好的,如果不同,则在调用A接口的方法时显示去让它去调用B类的方法,就达到了适配的目的。

对象适配,

有一个接口A,等待实现,有一个类B,具有可以替代A接口的功能,现在为了让B类的对象来帮接口A去做A的接口功能,使用对象适配,新建 适配器C,C继承于A,并在C的构造方法中传入B的实例对象,这时C持有对象B的实例,当接口A的方法被调用时,则使用对象B的实例方法来完成接口A的功能。

接口适配,

有一个接口A,拥有一些功能方法 ,有一个类B实现了A接口的方法 ,但类B只是想使用接口A中的一两个方法,如果B直接实现了A就会把A的很多无用方法也都带上,为了简洁则可以使用接口适配,新建一个抽象适配类C,C实现A接口,并将所有A类不想要的接口方法 都实现,其他想要的方法都不实现,交由C的子类D来实现;或者是都实现所有方法,然后再由C的子类去复写这些方法,达到不需要把接口方法都实现的目的。


桥接模式:

桥接模式是为了解决一个通用的逻辑具有多个维度的变化问题,像巴士跟小车都能在公路上跑,也都能在高速路上跑。总的逻辑是车在路上跑,但是车会有多种车,路也可能有多种路,这时使用桥接模式来适应这种变化 。新建抽象变化类A,它的实现B和C,新建抽象变化类D,它的实现E和F,A实现了两个变化类的逻辑关系方法,并持有一个D的实例,A的子类去实现D的实例初始化,最终完成D的调用 ,至于调用的是哪种类型 的D,它不用知道,让子类去实现就可以。


组合模式:

一个统一的节点接口,子节点实现节点接口,父节点也实现节点接口并且持有子节点对象列表。


装饰者模式:

有一个接口A,A有一个功能方法method(),有一个类B,B实现了A接口,现在想要实现在A调用method方法之前先做一些别的事情,并且不应该去修改method方法,这时就可以用上装饰模式,新建一个装饰类C,C实现了A接口,C的构造方法传入一个A的实现对象,也就是B对象,在C中的method方法中,添加要做一事情然后再使用B对象调用method,这样就实现了对方法method的功能装饰,而且是动态的,常适用于功能增强。装饰模式与适配器模式很像,但理念不同,适配模式是为了让本不兼容的两个类兼容,而装饰模式是让某个类增加一些功能,或者添加某些功能的表现。


代理模式:

有一个接口A,A有一个功能方法method(),有一个类B,B实现了A接口,现在想要实现对method方法管控,比如修改表现,增加方法之前的一些操作等,并且不应该去修改method方法,这时就可以用上代理模式,新建一个代理类C,C实现了A接口,C的构造方法传入一个A的实现对象,也就是B对象,在C中的method方法中,添加要做一事情然后对B对象调用method做管控,这样就实现了一个A的代理。代理模式与装饰模式非常像,但是理念不同,代理是为了完成对方法的修改管控,而装饰是为了增强功能。


外观模式:

故名思义,就是某种功能依赖于多个小功能,那么就用一个类将这些功能包装起来去实现,形成一个单一的组合功能,对外提供一个统一的接口方法,让外部调用,这样能降低代码的偶合度。比如有一个功能叫安装电脑,安装电脑的步骤为对cpu的安装,对主板的安装,对内存的安装,原则顺序来说又要先安装主板然后安装cpu再安装内存条。这些模式的安装都有准备,开始,完成的方法。当各个模块都做好后,这时可以新建一个类A来完成这些模块的操作,并且提供通用的方法,如准备,开始,完成曝露给外部调用。类A持有各个模块的实例,在类A的准备方法中,让各个模块去调用自己的准备方法来完成模块初始化,其他依次类推。


享元模式:

对于可能会创建多个对象的数据进行缓存,使用一个表来存储已经创建的数据下次还需要使用的话,直接从表中取,如果取到则返回,取不到则创建一个新的对象并添加到表中。


行为模式


中介者模式:

主要处理有相互的复杂同事关系,有一个工作的接口A,定义了一系列的工作,有多个同事类B,C,D,同事类B在处理自己的工作之前需要C的支持,处理完自己的工作后就到D去处理D工作,这就出现很多相互的关系,这时新建一个中介类M,向外提供一个将同事类添加到自己持有的通过名称来映射的同事列表方法 和同事的一些需要使用的工作方法。所有的同事类都持有中介类的实例,当同事类需要其他同事的协作时,则通过自己持有的中介,传入想要协助的同事名称 让中介去帮它做让指定人协作的事情。中介类收到命令就会从自己持有的同事列表中取出对应的同事来完成协作。


观察者模式:

当出现多个实例对同一个实例对象的变化感兴趣,并会根据此对象的变化而做出相应行为时,可以考虑使用观察者模式。新建一个类A做为被观察的对象类,建一个接口B作为要观察A变化的观察者,类C,D分别实现接口B成为观察者,类A维护一个B的列表,用来维护观察它的对象列表,并对外提供添加观察和取消观察的方法,当A发生变化时,取出A维护的B列表,并出发B类的统一方法。则所有注册到A的观察者都能收到A变化的消息。也可以使用Java本身的观察者来实现,被观察的类继承于Observable,观察者实现Observer接口,在被观察者数据发生变化时想要通知观察者时则先调用setChanged设置当前对象数据已发生变化,然后再调用notifyObservers方法来完成对观察者的广播。


命令模式:

适用于包含命令发送和处理的场景,比如经常会有客户端向处理器发送一个命令值,然后通过switch(cmd) case来判断使用不同的接收者来执行事务。这时可采用命令模式完成接收都与发送方的解偶,模拟电脑开机。有一个接主板类A,其中有一个方法 work();这是每一个接收都的工作方法,也可以定成一个模块工作接口。新建一个命令接口B,接口有一个需要子类实现的执行方法excute();新建一个命令类比如开机OpenBimpl,实现B命令接口,并在OpenBimpl的构造函数中传入一个主板类A的实例,以此来把主板绑定到这个开机命令上,并在实现的excute执行方法 里,使用持有主板实例调用主板实例的A.work();方法。表示当这个命令被发送时由主板来完成工作。新建一个负责命令的调用者机箱Box,机箱有两个方法 ,一个是开机按钮被按下时候所要执行的方法openCmdDo(){B.excute()},另一个是设置当开机按钮方法执行时,应该执行的命令setOpenCmd(B b)。客户端新建一个调用者Box实例,并设置好各个命令按钮,就可以开始发送命令了。当然调用都Box中也可以维护一个命令队列来保存多个命令,直接开始发送命令的时候再从队列中取出命令并执行。也可以演变成多线程命令,就是调用者只负责维护命令队列,并提供添加命令到队列的接口。而再多新加一个取命令并执行的类,来不停的去取调用者中的命令队列,如果队列中有命令就取出来执行,如果队列没有数据则等待,直到有新添加的命令就唤醒取命令的线程。


迭代器模式:

对于不同的数据集合,建立统一的迭代数据的方法 。新建迭代接口A,新建类B和C实现A接口,分别用于不同的数据的迭代,这些接口持有数据实例。完成统一数据迭代。


模板方法模式:

两个相似功能的类,但是他们的实现却不同。新建一个抽象类A把它们相同的功能方法抽象出来,再定义好统一的操作实现,并将不同的实现方法延迟到子类来实现。集合比较接口就用了此模式。


策略模式:

与模式板方法相似,对于相同的功能,不同的实现,使用接口来定义功能,而子类来完成实现。客户端来决定使用哪个实现来完成工作并且可以自由的切换。


状态模式:

带有状态的业务,将定义一个状态接口A,接口实现功能方法比如当此状态成功后将会进入哪种状态,失败后又会进入哪种状态,如果有通用的方法可以建立一个抽象类B,实现A接口并,完成一些通用方法的实现,之后列出所可能的状态继承于B,新建一个状态机控制类C,C持有当前状态的一个实例,并向外提供设置当前状态的方法,和获得当前状态的方法,另外还应该提供一个对外的去触发当前状态的方法,此方法被外界触发后会使用当前持有状态实例调用状态的通用函数,状态类持有状态机实例这样可以在自己的想要改变成别的状态时通过持有状态机实例调用设置状态的方法将状态机持有状态改变成想要设置的状态。


备忘录模式:

针对于可能需要保存状态恢复状态的操作,原理是建立一个类,此类中包含需要对原类备忘的属性,利用第三方来实现备忘的新建的恢复。对于原类A有一个value属性可能需要备忘,新建一个备忘录接口B,该接口是一个空接口,是为了给外部使用,但外部并不知道要备忘的是什么东西,也不能去修改备忘的东西,在原类A中新建一个内部类C,C实现B接口,并在B中增加一个属性value,value只实现get方法,并在B的构造函数中传入value完成初始化。原类A提供两个方法,一个是建立一个备忘,建立备忘返回一个备忘接口B的C实现实例,另一个是恢复备忘,提供一个方法由外部传入一个备忘B,并将其强转为备忘实现C,然后取得value给原类A设置其value值,完成备忘恢复。新建一个负责保存备忘的类D,D持有一个备忘实例,并向外提供了get,set方法来实现备忘存储的取出。客户端新建一个原类A的实例,执行备忘创建得到一个B的实例,新建C的实例,并将B存储到C中,原类A做了一些更改后,想要恢复到初始,从C中取出存储的备忘B,并通过原类A的恢复备忘方法利用备忘B来完成恢复


解释器模式:

对多种一样的问题,可以归纳为一种文法,并去解析这种文法。


职责链模式:

当发出一个请求,需要经过一条流程,这个流程中应该有一个对象来处理这个请求,如果它不能处理就把这个请求转交给下一个流程来处理。新建一个流程抽象类A,用来代表处理的流程,抽象类A持有下一个流程的实例,并提供一个方法来设置下一个流程的实例,抽象类A还提供一个处理的抽象方法。新建流程子类B,C,客户端实例B和C,并给B设置它的下一个处理流程为C,当有多个流程时,处理方法一样。这样就形成了一条链,当请求走到此流程的处理函数时,如果当前流程能处理则处理,不能处理则转交给它持有的下一个流程来处理,如果没有持有下一个流程又不能处理则请求结束。


访问者模式:

-----


设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

5、迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。


原创粉丝点击