设计模式(DesignPattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
依据目的划分:
创建型模式 | 用于创建对象 | 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 |
结构性模式 | 处理类或对象的组合 | 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 |
行为型模式 | 描述类与对象怎样交互、怎样分配职责 | 策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 |
2.依据作用范围划分:
描述 | 创建型 | 结构型 | 行为型 | |
类模式 | 用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。 | 工厂方法模式 | 适配器模式 | 模板方法模式 解释器模式 |
对象模式 | 用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。 | 抽象工厂模式 单例模式 建造者模式 原型模式 | 装饰器模式 代理模式 外观模式 桥接模式 组合模式 享元模式 | 策略模式 观察者模式 迭代子模式 责任链模式 命令模式 备忘录模式 状态模式 访问者模式 中介者模式 |
3.23种设计模式的功能
单例模式(Singleton):
保证一个类仅有一个实例,并提供一个访问它的全局访问点。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。
抽象工厂模式(Abstract Factory):
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
原型模式(Prototype):
用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。原型模式类似于细胞分裂,细胞在一定条件下,由一个分裂成2个,再由2个分裂成4个……,这个原始的细胞决定了分裂出来的细胞的组成结构。Prototype类中包括一个clone方法,Client调用其拷贝方法clone即可得到实例,不需要手工去创建实例。
建造者模式(Builder):
将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 典型的KFC儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。
使用建造者模式的好处:
1.使用建造者模式可以使客户端不必知道产品内部组成的细节。
2.具体的建造者类之间是相互独立的,对系统的扩展非常有利。
3.由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
工厂模式(Factory Method):
定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使一个类的实例化延迟到其子类。在此模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类负责生产具体的产品对象,使一个类的实例化延迟到其子类,由子类来确定实例化哪个具体的产品类
外观模式(Facade):
为子系统中的一组接口提供一个一致的界面,外观模式通过提供一个高层接口,隔离了外部系统与子系统间复杂的交互过程,使得复杂系统的子系统更易使用
桥接模式(Bridge):
将抽象部分与它的实现部分分离,使它们都可以独立地变化。 也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。
组合模式(Composite):
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。 组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象。
在水果盘(Plate)中有一些水果,如苹果(Apple)、香蕉(Banana)、梨子(Pear),当然大水果盘中还可以有小水果盘,现需要对盘中的水果进行遍历(吃),当然如果对一个水果盘执行“吃”方法,实际上就是吃其中的水果。 我们可以不管是大水果盘还是小水果盘,还是水果,都给它看做一个组件,该组件可以定义为抽象类,并且定义基本的抽象的吃方法,添加组件(组件可以是水果也可以是盘子)的方法,然后让水果类和盘子类分别继承组件类,并根据需要重写一些方法。
享元模式(Flyweight Pattern):
运用共享技术有效地支持大量细粒度的对象。 如:内衣工厂有100种男士内衣、100中女士内衣,要求给每种内衣拍照。如果不使用享元模式则需要200个塑料模特;使用享元模式,只需要男女各1个模特。 享元模式使系统使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。又称为轻量级模式。享元模式通过共享技术实现相同或相似对象的重用。
代理模式(Proxy Pattern):
为其他对象提供一种代理以控制对这个对象的访问。代理模式使用代理对象完成用户请求,屏蔽用户对真实对象的访问。现实世界的代理人被授权执行当事人的一些事宜,无需当事人出面,从第三方的角度看,似乎当事人并不存在,因为他只和代理人通信。而事实上代理人是要有当事人的授权,并且在核心问题上还需要请示当事人。
代理模式和适配器模式应该说很相像,但是他们的区别也很明显,代理模式和被代理者的接口是同一个,只是使用中客户访问不到被代理者,所以利用代理间接的访问,而适配器模式,是因为接口不同,为了让用户使用到统一的接口,把原先的对象通过适配器让用户统一的使用,大多数运用在代码维护的后期,或者借用第三方库的情况下 ,而外观模式,是大家经常无意中使用的,就是把错综复杂的子系统关系封装起来,然后提供一个简单的接口给客户使用,就类似于一个转接口。
装饰模式(Decorator):
动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。是在不改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。比如,我们有一杯“茉莉茶”,现在加上一颗“柠檬”,那我们就有了一杯“柠檬茉莉花茶”。“柠檬”作为一个装饰者,提供了“茉莉茶”本身没有的清爽口感。当然,这也带来了一定的负担,你需要花更多的“钱”。
装饰者模式通过组合的方式扩展对象的特性,这种方式允许我们在任何时候对对象的功能进行扩展甚至是运行时扩展,而若我们用继承来完成对类的扩展则只能在编译阶段实现,所以在某些时候装饰者模式比继承(inheritance)要更加灵活。
适配器模式(Adapter):
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。如: 电源适配器。
Adapter模式适用于:
想使用一个已经存在的类,而它的接口不符合你的需求。
想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(接口不一定兼容的类)协同工作
观察者模式(Observer Pattern):
观察者模式定义了对象间的一种一对多依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
发生改变的对象称为观察目标,被通知的对象称为观察者
一个观察目标可以对应多个观察者
模板方法(Template Pattern):
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。
在银行办理业务的时候,步骤一般是,排队取号、等待叫号、办理业务、为银行柜员打分,这个流程无论是办理存款、取款还是转账业务都是一样的
迭代模式(Iterator Pattern):
提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
如看电视换频道,我们可以遍历所有的频道而不需要知道频道间是如何转换的
策略模式(Strategy Pattern):
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机。每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度
责任链模式(Chain of Responsibility Pattern)
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
如申请报销费用,大致流程一般是,由申请人先填写申请单,然后交给领导审批,如果申请批准下来,领导会通知申请人审批通过,然后申请人去财务领取费用,如果没有批准下来,领导会通知申请人审批未通过,此事也就此作罢。
不同级别的领导,对于审批的额度是不一样的,比如,项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请
当某人提出报销申请的请求后,该请求会经由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求。申请人只要直接与项目经理交互就可以,其余的工作在黑盒中,究竟流程是怎样的,最后是由谁审批通过的,申请人无需关心。
命令模式(Command Pattern):
将一个请求封装成一个对象,从而使得用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
命令模式将发出命令的责任和执行命令的责任分割开。请求的一方不必知道接收请求的一方的接口,也不必知道请求是怎么被接收的,以及操作是否被执行、何时被执行以及怎样被执行的。
这就好像以前电视没有遥控的时候,如果你想更换频道的话,必须跑到电视机前,手动按换台按钮,如果台很多的话,而你家的电视又比较古老,那么你就得更辛苦一点,得手动调出来其他频道。现在有了遥控器,解放了我们,我们(相当于请求者),想换台,不用跑来跑去的调台,而是向电视机发出换台的请求,遥控器接收到我们的请求后,对电视发出具体的命令,是换台,关机,还是开机。这样,我们把请求传给遥控器,遥控器来具体执行需要哪些命令。这样,我们就和电视机解耦了。虽然结果是一样的,都是换了台,但是过程确截然不同。我们和电视之间没有任何联系了。 而联系只存在于遥控器和具体的命令,以及命令和电视之间了。
中介模式(Mediator Pattern):
用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
比如系统和各个硬件,系统作为中介者,各个硬件作为同事者,当一个同事的状态发生改变的时候,不需要告诉其他每个硬件自己发生了变化,只需要告诉中介者系统,系统会通知每个硬件某个硬件发生了改变,其他的硬件会做出相应的变化。
访问者模式(Visitor Pattern):
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用与这些元素的新操作。即对于某个对象或者一组对象,不同的访问者,产生的结果不同,执行操作也不同
解释器模式(Interpreter Pattern):
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
例如:构造一个语言解释器,使得系统可以执行整数间的乘、除和求模运算。如用户输入表达式”2*3/4%5”
备忘录模式(Memento Pattern):
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状态。
如word的撤销键,简单的说备忘录模式就是在想让对象回到原来某个时间点的状态时,可以通过撤销来简单的实现。
状态模式(State Pattern):
对于对象内部的状态,允许其在不同的状态下,拥有不同的行为,对状态单独封装成类 。
例如:我有一个订单,订单状态有未提交,待审核,审核通过,审核失败四个状态,订单的变化应该是:点击提交订单时,订单状态由未提交变成待审核;点击审核(待审核的订单)订单,可以变成审核通过或审核失败。