设计模式
一、 提炼设计模式的几个原则:
(1)开闭原则:模块应对扩展开放,而对修改关闭。
(2)里氏代换原则:如果调用的是父类的话,那么换成子类也完全可以运行。
(3)依赖倒转原则:抽象不依赖细节,面向接口编程,传递参数尽量引用层次高的类。
(4)接口隔离原则:每一个接口只负责一种角色。
(5)合成/聚合复用原则:要尽量使用合成/聚合,不要滥用继承。
二、设计模式的功用?
设计模式能解决替换杂乱无章的代码,形成良好的代码风格代码易读,工程师们都能很容易理解增加新功能时不用修改接口,可扩展性强
稳定性好,一般不会出现未知的问题设计模式不能解决:
(1)设计模式是用来组织你的代码的模板,而不是直接调用的库;
(2)设计模式并非最高效,但是代码的可读性和可维护性更重要;
(3)不要一味追求并套用设计模式,重构时多考虑。
三、设计模式分类
1、创建型模式:
单例模式、工厂模式(简单工厂、工厂方法、抽象工厂)、创建者模式、原型模式。
*2、结构型模式:*结构型模式是解析类和对象的内部结构和外部组合,通过优化程序结构解决模块之间的耦合问题。
适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
代理模式、适配器模式、门面模式、装饰模式的区别
a、 相同之处:都封装一个内部对象,调用内部对象的方法
b、 不同之处:各自有各自的特性和应用场景,不能相互替代。所以用的时候要仔细分析用那种合适。
*3、行为型模式:*行为型模式就是描述类和对象之间的通信和职责的。简而言之,就是类和对象扮演什么角色,还有怎么扮演这个角色的问题。
大体上分为三个大类:常见模式、已知模式、深度模式
1、常见模式包括: 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、状态模式、职责链模式、策略模式
2、 已知模式包括:备忘录模式
3、深度模式包括:解释器模式 访问者模式
单例模式
目的:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
特点:
三私一公:私有的静态变量(存放实例),私有的构造方法(防止创建实例),私有的克隆方法(防止克隆对象),公有的静态方法(对外界提供实例)
应用场景:
程序应用中,涉及到数据库操作时,如果每次操作的时候连接数据库,会带来大量的资源消耗。可以通过单例模式,创建唯一的数据库连接对象。数据库连接、缓存操作、分布式存储。
创建者模式
在创建者模式中,客户端不再负责对象的创建与组装,而是把这个对象创建的责任交给其具体的创建者类,把组装的责任交给组装类,客户端支付对对象的调用,从而明确了各个类的职责。
应用场景:创建非常复杂,分步骤组装起来。使用创建者模式对内部数据复杂的对象封装数据组装过程后,对外接口就会非常简单和规范,增加修改新数据项也不会对外部造成任何影响。
工厂模式
特点:
将调用对象与创建对象分离,调用者直接向工厂请求,减少代码的耦合.提高系统的可维护性与可扩展性。
应用场景:
提供一种类,具有为您创建对象的某些方法,这样就可以使用工厂类创建对象,而不直接使用new。这样如果想更改创建的对象类型,只需更改该工厂即可。
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
应用场景: 类的资源非常多、性能和安全要求,一般和工厂方法结合使用。
注册树模式
特点:
注册树模式通过将对象实例注册到一棵全局的对象树上,需要的时候从对象树上采摘的模式设计方法。
应用:
不管你是通过单例模式还是工厂模式还是二者结合生成的对象,都统统给我“插到”注册树上。我用某个对象的时候,直接从注册树上取一下就好。这和我们使用全局变量一样的方便实用。而且注册树模式还为其他模式提供了一种非常好的想法。 (如下实例是单例,工厂,注册树的联合使用)
策略模式
定义:
定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
特点:
策略模式提供了管理相关的算法族的办法; 策略模式提供了可以替换继承关系的办法;使用策略模式可以避免使用多重条件转移语句。
应用场景:
多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。比如上学,有多种策略:走路,公交,地铁…
适配器模式
特点:
将各种截然不同的函数接口封装成统一的API。将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
应用:
PHP中的数据库操作有MySQL,MySQLi,PDO三种,可以用适配器模式统一成一致,使不同的数据库操作,统一成一样的API。类似的场景还有cache适配器,可以将memcache,redis,file,apc等不同的缓存函数,统一成一致。老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立变化
特点:独立存在,扩展性强
应用:需要不断更换调用对象却执行相同的调用方法,实现扩展功能
装饰模式
动态地给一个对象添加额外的职责。在原有的基础上进行功能增强。
特点:用来增强原有对象功能,依附于原有对象。
应用:用于需要对原有对象增加功能而不是完全覆盖的时候,在多层关系的情况下,装饰是和顺序无关并且随时增加装饰,而继承只能是特定的顺序,所以装饰模式会更加的灵活。
组合模式
将对象组合成树形结构表示“部分-整体”的层次结构。
特点:灵活性强
应用:对象的部分-整体的层次结构,模糊组合对象和简单对象处理问题,例如登录信息,如果要增加登录次数、最后登录时间、登录ip等信息,登录本身就会变成一个比较复杂的对象。如果以后有新的需求比如好友信息、用户的访问信息等,再要继承的话,用户类就会变得非常庞大,难免各父类之间没有冲突的变量和方法,而外部访问用户类的众多方法也变得很费劲。采用组合模式后,一个类负责一个角色,功能区分非常明显,扩展方便
外观模式(门面模式)
为了系统中的一组接口提供一个一致的界面
特点:向上抽取,有共性
应用:内部接口众多,由统一的接口来调用,接口较多时把相似功能的接口封装成一个接口供外部调用,这就是门面模式
享元模式
运用共享技术有效地支持大量细粒度对象,采用一个共享来避免大量有相同内容对象的开销。这种开销中最直观的就是内存的损耗。
特点:高效性,共享性
应用:系统底层的设计。例如字符串的创建。如果两个字符串相同,则不会创建第二个字符串,而是第二个的引用直接指向第一个字符串。
s
t
r
1
=
”
a
b
c
”
,
str1=”abc”,
str1=”abc”,str2=”abc”.则内存存储中只会创建一个字符串“abc”而引用
s
t
r
1.
str1.
str1.str2都会指向它。
代理模式
为其他对象提供一个代理来控制对这个对象的访问,就是给某一对象提供代理对象,并由代理对象控制具体对象的引用。能够协调调用者和被调用者,能够在一定程度上降低系统的耦合性。
应用:客户访问不到或者被访问者希望隐藏自己,所以通过代理来访问自己。
观察者模式
特点:
观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新。观察者模式实现了低耦合,非侵入式的通知与更新机制。又叫发布订阅模式,当一个主体对象发生改变时,依赖它的多个观察 者对象都得到通知并自动更新响应。就像报社一样,今天发布的消息只要 是看这份报纸的人看到的都是同样的内容。如果发布另一份报纸,也是一 样的。
特点:低耦合性,独立性好,安全性
好处:广播式通信,范围大一呼百应,便于操作一个组团,“公有制”。
弊端:不能单独操作组团里的个体,不能实行按需分配。
应用:
操作多个对象,并操作相同。一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。
模版方法模式(Template):
定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中实现。 就像一个豆浆机,不管放进去的是红豆还是黑豆,出来的都是豆浆。
好处:扩展性好,封装不变的代码,扩展可变的代码。
弊端:灵活性差,不能改变骨架部分。
应用场景:一类或一组具有共性的事物中。
命令模式(Command) :
行为请求者与行为实现者解耦。就像军队里的“敬礼”,不管是谁听到 这个命令都会做出标准的敬礼动作。
好处:便于添加和修改行为,便于聚合多个命令。
弊端:造成过多具体的命令类。
应用场景:对要操作的对象,进行的相同操作。
迭代器模式(Iterator):
访问聚合对象内容而不暴露内部结构。就像一个双色球彩票开奖一 样,每次都是摇出七个球,不能能摇不是七个球的中奖号码组合。
好处:以不同方式遍历一个集合。
弊端:每次遍历都是整个集合,不能单独取出元素。
应用场景:需要操作集合里的全部元素。
中介者模式(Mediator):
用中介对象封装一系列的对象交互,中介使各对象不需要显式地相互引 用。类似于邮局,邮寄者和收件者不用自己跑很远路,通过邮局就可以。
好处:简化了对象之间的关系,减少子类的生成。
弊端:中介对象可能变得非常复杂,系统难以维护。
应用场景:不需要显示地建立交互
状态模式(State) :
对象在不同状态下表现出不同的行为。就像女朋友一样,高兴了牵你的 手,不高兴了遛狗。在两种状态下变现出不同的行为。
好处:避免if语句实用,方便增加新状态,封装了状态转换规则。
弊端:增加系统类和对象的数量。
应用场景:用于对象的不同功能的转换。
职责链模式 (Chainof Responsibility):
多个对象有机会处理请求,为请求发送者和接收者解耦。就像银行里 的取款机,不管那一台都可以取到钱。
好处:简单化对象隐藏链结构,便于添加新职责节点。
弊端:请求可能没有接受者,或者被多个接收者调用,性能降低。
应用场景:处理多种请求。
策略模式(Strategy):
定义一系列算法,把每一个算法封装起来,并且使它们可相互替换。 就像篮球队里的球员,场上的和场下休息的。教练可以让场上的下来,也 可以让场下的上阵。
好处:定义可重用的一系列算法和行为,并且消除了if else语句。
弊端:调用端必须知道所有策略类。
应用场景:用于对象间的替换。
备忘录模式(Memento):
保存对象在一时刻的状态。亲,还记得“老师来了记得叫我一下”的 同桌的他吗?
好处:给用户提供了一种可以恢复状态的机制。
弊端:消耗资源。
应用场景:用于需要保存的数据。
解释器模式(Interpreter):
定义语言的文法,并建立一个解释器解释该语言中的句子。每个用过 字典的童鞋都懂滴。
好处:可扩展性比较好,灵活性大
弊端:可能难以维护复杂的文法
应用场景:用于成对或者一对多的需求中
访问者模式(Visitor):
封装某些用于作用于某种数据结构中各元素的操作,可以在不改变数 据结构的前提下定义作用于这些元素的新操作。如银行排号机。
好处:将相关的事物集中到一个访问者对象中。
弊端:增加新数据结构很困难。
应用场景:排队,排号。
总结
本篇介绍了行为型模式,行为模式涉及到算法和对象职责间的分配,行为类 模式采用继承机制在类间分派行为,TemplateMethod和Interpreter是类行为 模式。行为对象模式使用对象复合而不是继承,一些行为对象模式描述了一组相 互对等的对象如何相互协作以完成其中任何一个对象都单独无法完成的任务,如 Mediator在对象间引入一个mediator对象提供了松耦合所需的间接性; Chain of Responsibility提供了更松的耦合,它通过一条候选对象链隐式的向一 个对象发松请求,可以运行时刻决