软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
一、基础
软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
二、分类
创建型
Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点
单例模式(Singleton Pattern)是最简单的设计模式之一,属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。另外,该类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例,即一个类只有一个实例,并提供一个全局访问点。
单例模式需要满足以下四个条件:
- 私有化构造函数
- 私有化克隆函数
- 私有化静态成员变量
- 公有化获取静态实例方法
优点
- 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例
- 单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性
- 提供了对唯一实例的受控访问
- 由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能
- 允许可变数目的实例
- 避免对共享资源的多重占用
缺点
- 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态
- 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难
- 单例类的职责过重,在一定程度上违背了“单一职责原则”
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失
适用场景
- 外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。
- 内部资源:大多数软件都有个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
- Windows系统的任务管理器
- windows系统的的回收站
- 网站的计数器
- 应用程序的日志应用
- Web应用的配置对象的读取
- 数据库连接池的设计
- 多线程的线程池的设计
- 操作系统的文件系统
- HttpApplication
- 外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。
销毁
- 系统自动回收
- 手动回收
Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。
Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。
Builder,建造者模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。
Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。
结构型
- Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。
- Facade,外观模式:为子系统中的一组接口提供一致的界面,fa?ade提供了一高层接口,这个接口使得子系统更容易使用。
- 一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。
- 该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
- 该模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
- 优点
- 减少系统相互依赖
- 提高灵活性
- 提高了安全性。
- 缺点
- 不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
- 适用场景
- 为复杂的模块或子系统提供外界访问的模块
- 子系统相对独立
- 预防低水平人员带来的风险
- Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问
- Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。
- Decrator,装饰者模式:动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。
- 装饰者模式(Decorator Pattern),指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
- 它是通过创建一个包装对象,也就是装饰来包裹真实的对象
- 优点
- 该模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性
- 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合
- 缺点
- 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性
- 装饰模式会导致设计中出现许多小类,如果过度使用会使程序变得很复杂
- 装饰模式是针对抽象组件(Component)类型编程
- 适用场景
- 扩展一个类的功能
- 动态增加功能,动态撤销
* Bridge,桥接模式:将抽象部分与它的实现部分相分离,使他们可以独立的变化。 * Flyweight,享元模式:尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。主要用于减少创建对象的数量,以减少内存占用和提高性能。
行为型
- Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。
- Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。
- 观察者模式,又被称为模型-视图模式、源-收听者模式、从属者模式,是软件设计模式的一种。在此模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。
- 通常通过呼叫各观察者所提供的方法来实现。
- 通常被用来实现事件处理系统。
- 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 实现要点
- Subject类:包含绑定和移除观察者及通知方法
- Observer类:抽象类,定义抽象方法及subject实例
- Client类:继承抽象类Observer,重写父类方法
- 优点
- 观察者和被观察者是抽象耦合的
- 建立一套触发机制
- 缺点
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化
- 适用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
- Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。
- Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。
- State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。
- Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。
- 优点
- 算法可以自由切换
- 避免使用多重条件判断
- 扩展性良好
- 缺点
- 策略类会增多
- 所有策略类都需要对外暴露
- 适用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
- 一个系统需要动态地在几种算法中选择一种
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现
- 优点
- Chain of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系
- Mediator,中介者模式:用一个中介对象封装一些列的对象交互。
- Visitor,访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。
- Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
- Memento,备忘录模式:在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
三、实现
- 策略模式
1 | interface Strategy |
外观模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60interface Shape
{
public function draw();
}
class Circle implements Shape
{
public function draw()
{
echo "圆形", PHP_EOL;
}
}
class Square implements Shape
{
public function draw()
{
echo "正方形", PHP_EOL;
}
}
class Triangle implements Shape
{
public function draw()
{
echo "三角形", PHP_EOL;
}
}
class ShapeFacade
{
private $circle;
private $triangle;
private $square;
public function __construct()
{
$this->circle = new Circle();
$this->triangle = new Triangle();
$this->square = new Square();
}
public function drawCircle(){
$this->circle->draw();
}
public function drawSquare()
{
$this->square->draw();
}
public function drawTriangle()
{
$this->triangle->draw();
}
}
$shape = new ShapeFacade();
$shape->drawCircle();
$shape->drawSquare();
$shape->drawTriangle();适配器模式
1 | interface MediaPlayer |
- 简单工厂
1 | abstract class Car |
- 工厂方法
1 | interface CarFactory //也可用抽象类 |
- 抽象工厂
1 | interface AbstractCarFactory |
- 单例模式
1 | class Singleton |
- 装饰者
1 | interface Shape |
- 观察者模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100class Subject
{
public $state = '';
public $observers = [];
public function getState()
{
return $this->state;
}
public function setState($state)
{
$this->state = $state;
$this->notifyAllClient();
}
public function bind(Observer $observer)
{
$this->observers[] = $observer;
}
public function unbind(Observer $observer)
{
foreach ($this->observers as $key => $val) {
if ($val == $observer) {
unset($this->observers[$key]);
}
}
}
public function notifyAllClient()
{
foreach ($this->observers as $item) {
$item->update();
}
}
}
abstract class Observer
{
public $subject;
public abstract function update();
}
class ClientA extends Observer
{
public $state = '初始状态A';
public function __construct(Subject $subject)
{
$this->subject = $subject;
$this->subject->bind($this);
}
public function update()
{
$this->state = $this->subject->getState();
}
public function getState()
{
return "ClientA状态:".$this->state;
}
}
class ClientB extends Observer
{
public $state = '初始状态B';
public function __construct(Subject $subject)
{
$this->subject = $subject;
$this->subject->bind($this);
}
public function update()
{
$this->state = $this->subject->getState();
}
public function getState()
{
return "ClientB状态:".$this->state;
}
}
$subject = new Subject();
$a = new ClientA($subject);
$b = new ClientB($subject);
// print_r($subject->observers);
echo $a->getState(),PHP_EOL;
echo $b->getState(),PHP_EOL;
$subject->setState("123");
echo $a->getState(),PHP_EOL;
echo $b->getState(),PHP_EOL;
// $subject->unbind($a);
// print_r($subject->observers);