介绍
结构型模式是解析类和对象的内部结构和外部组合,通过优化程序结构解决模块之间的耦合问题。种类:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
适配器模式(adapter)
- 介绍
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
- 代码示例
1 | <?php |
注意:这里的新接口使用了组合方式,UserInfo内部有一个成员变量保存老接口User对象,模块之间是松耦合的,这种结构其实就是组合模式。不要使用继承,虽然UserInfo继承User也能达到同样的目的,但是耦合度高,相互产生影响。
桥接模式(bridge)
- 介绍
将抽象部分与它的实现部分分离,使它们都可以独立变化。特点:独立存在,扩展性强。应用:需要不断更换调用对象却执行相同的调用方法,实现扩展功能。
- 代码示例
1 | <?php |
装饰模式(decorate)
- 介绍
动态地给一个对象添加额外的职责。在原有的基础上进行功能增强。特点:用来增强原有对象功能,依附于原有对象。应用:用于需要对原有对象增加功能而不是完全覆盖的时候。
- 代码示例
1 | <?php |
组合模式(combination)
- 介绍
将对象组合成树形结构表示“部分-整体”的层次结构。特点:灵活性强。应用:对象的部分-整体的层次结构,模糊组合对象和简单对象处理问题。
- 代码示例
1 | <?php |
上面面的例子分别展示了使用继承和组合来处理新功能,在简单的情况下看似区别不大,但在项目后期越来越复杂的时候组合模式的优势就越来越明显了。例如上面的登录信息,如果要增加登录次数、最后登录时间、登录ip等信息,登录本身就会变成一个比较复杂的对象。如果以后有新的需求比如好友信息、用户的访问信息等,再要继承的话,用户类就会变得非常庞大,难免各父类之间没有冲突的变量和方法,而外部访问用户类的众多方法也变得很费劲。采用组合模式后,一个类负责一个角色,功能区分非常明显,扩展方便。
外观模式/门面模式(appearance)
- 介绍
为了系统中的一组接口提供一个一致的界面。特点:向上抽取,有共性。应用:内部接口众多,由统一的接口来调用。
代码示例
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<?php
/**
*
* 外观模式,也叫门面模式
*
*/
class Operation {
public function testPlus() {
printf("plus: %s\n", (1+2 == 3 ? 'true' : 'false'));
}
public function testMinus() {
printf("minus: %s\n", (3-2 == 2 ? 'true' : 'false'));
}
public function testTimes() {
printf("times: %s\n", (2*3 == 6 ? 'true' : 'false'));
}
}
class Tester {
protected $_operation;
function __construct() {
$this->_operation = new Operation();
}
public function testAll() {
$this->_operation->testPlus();
$this->_operation->testMinus();
$this->_operation->testTimes();
}
}
//测试用例,测试全部接口
$tester = new Tester();
$tester->testAll();
?>
门面模式估计大家在实际代码中都已经使用到了,接口较多时把相似功能的接口封装成一个接口供外部调用,这就是门面模式。
代理模式(agency)
- 介绍
为其他对象提供一个代理来控制对这个对象的访问,就是给某一对象提供代理对象,并由代理对象控制具体对象的引用。能够协调调用者和被调用者,能够在一定程度上降低系统的耦合性。特点:低耦合性,独立性好,安全性。应用:客户访问不到或者被访问者希望隐藏自己,所以通过代理来访问自己。
- 代码示例
1 | <?php |
总结
模式的选用要根据实际的业务需求,通过对业务逻辑的仔细分析,再根据模式具有的特性和应用场景进行合理的选择和区分。大部分情况下业务的场景决定了哪种模式,而不是选择哪个模式去实现一个业务,少数情况几种模式确实都能解决问题,那主要就是考虑以后的扩展了。