设计模式笔记

六大原则

开闭原则

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭

单一职责原则

一个类只负责一项职责,部分方法可以整理到一起,抽出来来做为另外一个类, There should never be more than one reason to change a class. 应该永远只有一个理由来修改一个类

里氏替换原则

子类可以扩展父类的功能,但不能改变父类原有的功能。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。

Father f = new Son();
test((Son)f);

好的设计是: 子类继承父类,拥有父类的方法,可以新加方法,但是不能重写父类的方法。如果要实现多态,父类的方法就不要实现,全部由子类实现。 如果某个方法,很多个子类的实现都是一样的,只有一个子类的实现是不一样的,那这个子类可以考虑不用继承的方法来实现了,可以考虑抽出来一个接口,实现2个类,通过组合的方式加进去。

依赖倒置原则

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。

解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。

接口隔离原则

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上 问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。

解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。

迪米特原则

一个对象应该对其他对象保持最少的了解

创建型

简单工厂模式(静态工厂模式)

根据配置不同的参数,返回不同的具体产品。一个抽象产品类,多个具体产品类,一个工厂类,工厂类里面,调用一个方法,根据传进来的参数,返回不同的具体产品对象。

工厂方法模式

一个抽象产品类,多个具体产品类,一个抽象工厂类,多个具体工厂类,每个具体工厂类对应一个具体产品类,当需要扩展产品时,就增加一个具体产品类和一个具体工厂类。

抽象工厂模式

多个抽象产品类,每个抽象产品类对应多个具体产品类,一个抽象工厂类,多个具体工厂类,一个具体工厂类,调用2个方法,生产2种不同产品

建造者模式

一个指挥者,一个抽象建造者,一个具体建造者,一个产品。不断建造产品的一部分,最后形式一个产品。

单例模式

很简单,不多说

行为型

模板方法模式

父类中有一个方法,叫模板方法,调用了几个抽象保护方法,子类实现这个些抽象保护方法,客户端调用这个模板方法,以实现多态。

命令模式

为了将发起者和接收者解耦,引入这种模式。 引入一个新类,叫做命令类,它的成员是接收者。发起者的成员是命令类,发起时,调用命令类的方法,在命令类的方法中调用接收者的方法,这样子发起者只需要关心要发什么命令就行了。

策略模式

要去做一件事情,有几种不同的方法,每种方法就是一个策略。一个抽象策略类,很多具体策略类,一个环境类,环境类设置一个策略,然后使用某个方法做这件事情。

观察者模式

一个目标抽象类,一个目标具体类,一个观察者抽象类,一个观察者具体类。目标类里面有一个观察者列表,记录所有添加进去的观察者,当目标类要通知观察者时,会遍历整个列表,然后调用观察者的某个方法以达到目的。

中介者模式

一个类A,一个类B, 一个中间类M, 中间类M中维护一个列表,保存A和B的引用,中间类M都作为A和B的成员, 当A发送消息给B时,调用类M的一个方法,这个方法会找到接收者,然后调用接收者的接收消息的方法,这样子实现了A和B的解耦。

状态模式

一个上下文类Context, 一个抽象状态类,多个具体状态类,上下文类的一个成员是抽象状态类,客户端一直使用上下文类的一个方法,可以根据不同逻辑,改变抽象状态类的指向,调用状态类的方法,可以得到不同的结果,以产生不同的行为。

结构型

适配器模式

有一个旧类Old, 里面实现了一个方法play,有一个新类New,里面也实现了一个方法play。但是现在客户端想调用旧类的play方法,不想调用新的类,我们又不想继续在旧类的play方法上加代码,这个时间就可以用适配器模式。 新加一个Adapter类,跟Old类实现同一个接口,实现里面的play方法,实现中调用New类的play方法。 修改Old类的play方法,某种情况下调用Adapter类的play方法。这样就实现了适配的效果。 为什么不直接在Old类的play方法中调用New类的方法呢?因为这样下次要换另外一个的时候,就又要改Old类的代码,违反了开闭原则。使用适配器模式之后,如果增加拓展,只需要修改Adapter类,加一个要适配的类型。 Old类叫做Target目标者,New类叫做Adaptee适配者。

桥接模式

面对多维度变化导致的类爆炸问题,将继承变成组合的形式。 如果使用传统模式,则会有:达飞普通产品,达飞商城产品,我来贷普通产品,我来贷商户产品,会越来越多,桥接模式就是把产品抽出来,通过组合的方式来实现。 MallProduct里面,this.platformImpl.xxx 平台用各自实现,产品类型有各自实现,然后桥接起来

装饰模式

一个抽象基类,一个具体类,实现抽象基类。一个抽象装饰器类,实现抽象基类,多个具体装饰器类,继承抽象装饰器类。采用多态的方式,将抽象基类指针传进具体装饰器类里面,具体装饰器类组合抽象基类指针,由于这种关系,具体装饰器类的实例,它的基类也是抽象基类,所以对客户端透明,达到了包装的效果

门面模式

新建一个类,客户端只调用这个类的一个方法,这个方法根据一些情况去调用子系统里面不同模块的方法,以达到统一的作用,简洁易用

享元模式

其实就是内存共享,用一个工厂去取共享的对象,如果在内存中有,就直接返回

代理模式

一个抽象类,一个具体类,当需求变化,但是具体类又不能修改代码时,可以增加一个代理类,同样实现抽象类,具体类作为它的成员,扩展方法时调用具体类的旧代码,再加上新代码。 所谓的动态代理,是说在编译时不需要定义代理类,而是在运行时创建,这个是关键:在运行时创建代理类