目的
设计模式的目的是提高代码的重用性,可读性、可扩展性、可靠性,使程序呈现高内聚,低耦合的特性
原则
单一职责原则
假设有一个class负责两个职责,一旦发生需求变更,修改其中一个职责的逻辑代码,有可能会导致另一个职责的功能发生故障。这样一来,这个class就存在两个导致类变更的原因。如何解决这个问题呢?我们就要分别用两个Class来实现两个职责,进行解耦。后期需求变更维护互不影响。这样的设计,可以降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。
单一职责注意事项:
降低类的复杂度,一个类只负责一项职责;
提高类的可读性,可维护性;
降低变更引起的风险。
依赖倒置原则
依赖倒置原则(Dependency Inversion Principle, DIP) :指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。通过依赖倒置,可以降低类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并降低修改程序带来的风险。
依赖倒置原则注意事项:
变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化。
以抽象为基准比以细节为基准搭建起来的架构要稳定得多,因此大家再拿到需求后,要面向抽象编程,按照先顶层再细节的顺序设计代码结构。
开闭原则
开闭原则(Open-Closed Principle,OCP) :指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。强调的是用抽象构建框架,用实现扩展细节,当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化,可以提高软件系统的可复用性及可维护性。
本质:
其本质是指:当在一个设计中增加新的模块时,不需要修改现有的模块。
开闭原则是面向对象设计中最基础的设计原则,他的核心思想是面向抽象编程。
依赖倒置原则与开闭原则的关系:
依赖倒置原则是程序要依赖于抽象接口,不要依赖于具体实现。
当设计某些系统时,经常需要面向抽象来考虑系统的总体设计,不要考虑具体类,这样容易设计出满足“开-闭原则”的系统。
在程序设计好以后,首先要对抽象类(或接口)的修改关闭,否则,一旦修改抽象类(或接口),将可能导致它的所有子类(或实现类)都需要作出修改;应当对增加抽象类的子类(或接口的实现类)开放,即在增加新的子类(或实现类)时,不需要修改其他面向抽象类(或接口)而设计的重要类,例如案例中的Pillar类。
接口隔离原则
接口隔离原则(Interface Segregation Principle, ISP):指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。
接口隔离原则注意:
一个类对另一个类的依赖应该建立在最小接口上。
建立单一接口,不要建立庞大臃肿的接口。
尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)。
里氏替换原则
里氏替换原则(Liskow Substitution Principle,LSP) :如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P的所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
可以理解为一个软件实体如果适用于一个父类,则一定适用于其子类,所有引用父类的地方必须能透明地使用其子类对象,子类对象能够替换父类对象,而程序逻辑不变。也可以理解为,子类可以扩展父类的功能,但不能改变父类原有的功能。
迪米特法则
迪米特法则(Law of Demeter,LoD) :又叫最少知道原则,即一个类对自己依赖的类知道的越少越好,尽量降低类与类之间的耦合。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供public方法,不对外泄露任何信息。
迪米特法则还有个更简单的定义:只与朋友说话,不和陌生人说话。朋友:出现在成员变量、方法参数,方法返回值中的类为直接的朋友,出现在方法体内部的类不属于朋友类。
组合复用原则
组合复用原则(Composite Reuse Principle, CRP) :尽量使用对象组合(has-a)或对象聚合(contains-a)的方法实现代码复用,而不是用继承关系达到代码复用的目的。合成复用原则可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较小
设计原则 | 一句话归纳 | 目的 |
单一职责原则 | 一个类只干一件事 | 便于理解,提高代码可读性 |
依赖倒置原则 | 面向抽象 | 降低维护带来的新风险 |
开闭原则 | 对扩展开放,对修改关闭 | 更利于代码结构的升级扩展 |
接口隔离原则 | 一个接口只干一件事 | 提高内聚,减少对外交互 |
里氏替换原则 | 子类重写方法功能发生改变不应该影响父类方法的含义 | 提高代码健壮性及复用性 |
迪米特法则 | 不该知道的不要知道 | 解耦,高内聚,低耦合 |
组合复用原则 | 尽量是用组合实现代码复用,而不使用继承 | 降低类之间的耦合度 |
设计模式的分类
一般可以按照设计模式的目的(模式是用来做什么的)将其分为创建型(Creational),结构型(Structural)和行为型(Behavioral)3种:
创建型模式:主要用于创建对象。
结构型模式:主要用于处理类或对象的组合。
行为型模式:主要用于描述对类或对象怎样交互和怎样分配职责。
创建型模式:
涉及对象的实例化。这类模式的特点是,不让用户代码依赖于对象的创建或排列方式,避免用户直接使用new运算符创建对象。包括:
抽象工厂模式(Abstract Factory)
建造者模式(Builder):又称生成器模式
工厂方法模式(Factory Method)
原型模式(Prototype)
单例模式(Singleton) :又称单件模式
结构型模式:
涉及如何组合类和对象以形成更大的结构,和类有关的结构型模式涉及如何合理地使用继承机制,和对象有关的结构型模式涉及如何合理地使用对象组合机制。包括:
抽象适配器模式(Adapter)
桥接模式(Bridge)
组合模式(Composite)
装饰模式(Decorator)
外观模式(Facade)
享元模式(Flyweight)
代理模式(Proxy)
行为型模式:
涉及怎样合理地设计对象之间的交互通信,以及怎样合理地为对象分配职责,让设计富有弹性、易维护、易复用。包括:
职责链模式(Chain of Responsibility)
命令模式(Command)
解释器模式(Interpreter)
迭代器模式(Iterator)
中介者模式(Mediator)
备忘录模式(Memento)
观察者模式(Observer)
策略模式(Strategy)
状态模式(State)
模板方法模式(Template Method)
访问者模式(Visitor)
简单工厂模式
模式定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式的优点
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
简单工厂模式的缺点
由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。