标签归档:设计模式

PHP设计模式笔记:使用PHP实现桥梁模式

PHP设计模式笔记:使用PHP实现桥梁模式

【意图】
将抽象部分与它的实现部分分享,使它们都可以独立的变化【GOF95】

【桥梁模式结构图】

桥梁模式

桥梁模式

【桥梁模式中主要角色】
抽象化(Abstraction)角色:定义抽象类的接口并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(Implementor)角色:定义实现类的接口,不给出具体的实现。此接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以完全不同。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
具体实现化(Concrete Implementor)角色:实现实现化角色接口并定义它的具体实现。

【桥梁模式的优点】
1、分离接口及其实现部分
将Abstraction与Implementor分享有助于降低对实现部分编译时刻的依赖性
接口与实现分享有助于分层,从而产生更好的结构化系统

2、提高可扩充性

3、实现细节对客户透明。

【桥梁模式适用场景】
1、如果一个系统需要在构件的抽象化和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
2、设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
3、一个构件有多于一个的抽象化角色和实现化角色,并且系统需要它们之间进行动态的耦合。
4、虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。

【桥梁模式与其它模式】
抽象工厂模式(abstract factory模式):抽象工厂模式可以用来创建和配置一个特定的桥梁模式。
适配器模式(adapter模式):适配器模式用来帮助无关的类协同工作。它通常是在系统设计完成之后才会被使用。然而,桥梁模式是在系统开始时就被使用,它使得抽象接口和实现部分可以独立进行改变。
状态模式(state模式):桥梁模式描述两个等级结构之间的关系,状态模式则是描述一个对象与状态对象之间的关系。状态模式是桥梁模式的一个退化的特殊情况。

【桥梁模式PHP示例】

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
100
101
102
103
<?php
/**
 * 桥梁模式 2010-06-06 sz
 * @author phppan.p#gmail.com  http://www.phppan.com
 * 哥学社成员(http://www.blog-brother.com/)
 * @package design pattern
 */
 
/**
 * 抽象化角色
 * 抽象化给出的定义,并保存一个对实现化对象的引用。
 */
abstract class Abstraction {
 
    /* 对实现化对象的引用 */
    protected $imp;
 
    /**
     * 某操作方法
     */
    public function operation() {
        $this->imp->operationImp();
    }
}
 
/**
 * 修正抽象化角色
 * 扩展抽象化角色,改变和修正父类对抽象化的定义。
 */
class RefinedAbstraction extends Abstraction {
 
     public function __construct(Implementor $imp) {
        $this->imp = $imp;
    }
 
    /**
     * 操作方法在修正抽象化角色中的实现
     */
    public function operation() {
        echo 'RefinedAbstraction operation  ';
        $this->imp->operationImp();
    }
}
 
/**
 * 实现化角色
 * 给出实现化角色的接口,但不给出具体的实现。
 */
abstract class Implementor {
 
    /**
     * 操作方法的实现化声明
     */
    abstract public function operationImp();
}
 
/**
 * 具体化角色A
 * 给出实现化角色接口的具体实现
 */
class ConcreteImplementorA extends Implementor {
 
    /**
     * 操作方法的实现化实现
     */
    public function operationImp() {
        echo 'Concrete implementor A operation <br />';
    }
}
 
/**
 * 具体化角色B
 * 给出实现化角色接口的具体实现
 */
class ConcreteImplementorB extends Implementor {
 
    /**
     * 操作方法的实现化实现
     */
    public function operationImp() {
        echo 'Concrete implementor B operation <br />';
    }
}
 
/**
 * 客户端
 */
class Client {
 
     /**
     * Main program.
     */
    public static function main() {
        $abstraction = new RefinedAbstraction(new ConcreteImplementorA());
        $abstraction->operation();
 
        $abstraction = new RefinedAbstraction(new ConcreteImplementorB());
        $abstraction->operation();
    }
}
 
Client::main();
?>

在写上面的代码时,就构造方法是否可以放在抽象化角色中纠结了许久!

PHP设计模式笔记:使用PHP实现装饰模式

PHP设计模式笔记:使用PHP实现装饰模式

【意图】
动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活【GOF95】
装饰模式是以对客户透明的方式动态地给一个对象附加上更多的职责。这也就是说,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。

【装饰模式结构图】

装饰模式

装饰模式

【装饰模式中主要角色】
抽象构件(Component)角色:定义一个对象接口,以规范准备接收附加职责的对象,从而可以给这些对象动态地添加职责。
具体构件(Concrete Component)角色:定义一个将要接收附加职责的类。
装饰(Decorator)角色:持有一个指向Component对象的指针,并定义一个与Component接口一致的接口。
具体装饰(Concrete Decorator)角色:负责给构件对象增加附加的职责。

【装饰模式的优缺点】
装饰模式的优点:
1、比静态继承更灵活;
2、避免在层次结构高层的类有太多的特征
装饰模式的缺点:
1、使用装饰模式会产生比使用继承关系更多的对象。并且这些对象看上去都很想像,从而使得查错变得困难。

【装饰模式适用场景】
1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2、处理那些可以撤消的职责,即需要动态的给一个对象添加功能并且这些功能是可以动态的撤消的。
3、当不能彩生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

【装饰模式与其它模式】

【装饰模式PHP示例】

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
100
101
102
103
104
105
106
107
108
109
110
111
112
 
 
<?php
/**
 * 装饰模式 2010-06-03 sz
 * @author phppan.p#gmail.com
 * http://www.phppan.com 哥学社成员(http://www.blog-brother.com/)
 * @package design pattern
 */
 
/**
 * 抽象构件角色
 */
interface Component {
    /**
     * 示例方法
     */
    public function operation();
}
 
/**
 * 装饰角色
 */
abstract class Decorator implements Component{
 
    protected  $_component;
 
    public function __construct(Component $component) {
        $this->_component = $component;
    }
 
    public function operation() {
        $this->_component->operation();
    }
}
 
/**
 * 具体装饰类A
 */
class ConcreteDecoratorA extends Decorator {
    public function __construct(Component $component) {
        parent::__construct($component);
 
    }
 
    public function operation() {
        parent::operation();    //  调用装饰类的操作
        $this->addedOperationA();   //  新增加的操作
    }
 
    /**
     * 新增加的操作A,即装饰上的功能
     */
    public function addedOperationA() {
        echo 'Add Operation A <br />';
    }
}
 
/**
 * 具体装饰类B
 */
class ConcreteDecoratorB extends Decorator {
    public function __construct(Component $component) {
        parent::__construct($component);
 
    }
 
    public function operation() {
        parent::operation();
        $this->addedOperationB();
    }
 
    /**
     * 新增加的操作B,即装饰上的功能
     */
    public function addedOperationB() {
        echo 'Add Operation B <br />';
    }
}
 
/**
 * 具体构件
 */
class ConcreteComponent implements Component{
 
    public function operation() {
        echo 'Concrete Component operation <br />';
    }
 
}
 
/**
 * 客户端
 */
class Client {
 
     /**
     * Main program.
     */
    public static function main() {
        $component = new ConcreteComponent();
        $decoratorA = new ConcreteDecoratorA($component);
        $decoratorB = new ConcreteDecoratorB($decoratorA);
 
        $decoratorA->operation();
        $decoratorB->operation();
    }
 
}
 
Client::main();
?>

从以上示例可以看出:
1、装饰类中有一个属性$_component,其数据类型是Component;
2、装饰类实现了Component接口;
3、接口的实现是委派给父类,但并不是单纯的委派,还有功能的增强;
4、具体装饰类实现了抽象装饰类的operation方法。

PHP设计模式笔记:使用PHP实现抽象工厂模式

PHP设计模式笔记:使用PHP实现抽象工厂模式
抽象工厂模式(Abstact Factory)是一种常见的软件设计模式。该模式为一个产品族提供了统一的创建接口。当需要这个产品族的某一系列的时候,可以为此系列的产品族创建一个具体的工厂类。

【意图】
抽象工厂模式提供一个创建一系统相关或相互依赖对象的接口,而无需指定它们具体的类【GOF95】

【抽象工厂模式结构图】

抽象工厂模式

抽象工厂模式


【抽象工厂模式中主要角色】
抽象工厂(Abstract Factory)角色:它声明一个创建抽象产品对象的接口。通常以接口或抽象类实现,所有的具体工厂类必须实现这个接口或继承这个类。
具体工厂(Concrete Factory)角色:实现创建产品对象的操作。客户端直接调用这个角色创建产品的实例。这个角色包含有选择合适的产品对象的逻辑。通常使用具体类实现。
抽象产品(Abstract Product)角色:声明一类产品的接口。它是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
具体产品(Concrete Product)角色:实现抽象产品角色所定义的接口,定义一个将被相应的具体工厂创建的产品对象。其内部包含了应用程序的业务逻辑。

【抽象工厂模式的优缺点】
抽象工厂模式的优点:
1、分离了具体的类
2、使增加或替换产品族变得容易
3、有利于产品的一致性

抽象工厂模式的缺点: 难以支持新种类的产品。这是因为AbstractFactory接口确定了可以被创建的产品集合。支持新各类的产品就需要扩展访工厂接口,从而导致AbstractFactory类及其所有子类的改变。
抽象工厂就是以一种倾斜的方式支持增加新的产品中,它为新产品族的增加提供了方便,而不能为新的产品等级结构的增加提供这样的方便。

【抽象工厂模式适用场景】
以下情况应当使用抽象工厂模式:
1、一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2、这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
3、 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
4、系统提供一个产品类的库,所有的产品以同样的接口出现,从而使用客户端不依赖于实现
【Java与模式189页】

Abstract Factory模式的几个要点:
1、如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式。
2、“系列对象”指的是这项对象之间有相互依赖、或作用的关系。
3、Abstract Factory模式主要在于应对“新系列”的需求变动。缺点是难以应对
“新对象”的需求变动。这一点应该注意,就像前面说的,如果我们现在要在加入
其他系列的类,代码的改动会很大。
4、Abstract Factory模式经常和Factory Method模式共同组合来应对
“对象创建”的需求变化。

抽象工厂中的增加
1. 在产品等级结构的数目不变的情况下,增加新的产品族,就意味着在每一个产品等级结构中增加一个(或者多个)新的具体 (或者抽象和具体)产品角色。 由于工厂等级结构是与产品等级结构平行的登记机构,因此,当产品等级结构有所调整时, 需要将工厂等级结构做相应的调整。现在产品等级结构中出现了新的元素,因此, 需要向工厂等级结构中加入相应的新元素就可以了。 换言之,设计师只需要向系统中加入新的具体工厂类就可以了,没有必要修改已 有的工厂角色或者产品角色。因此,在系统中的产品族增加时,抽象工厂模式是支持“开-闭”原则的。

2. 在产品族的数目不变的情况下,增加新的产品等级结构。换言之,所有的产品等级结构 中的产品数目不会改变,但是现在多出一个与现有的产品等级结构平行的新的产品等级结构。 要做到这一点,就需要修改所有的工厂角色,给每一个工厂类都增加一个新的工厂方法, 而这显然是违背“开–闭”原则的。换言之,对于产品等级结构的增加,抽象工厂模式是不支持“开–闭”原则的。

综合起来,我们可以知道,在已有的抽象产品中添加其具体产品,支持“开—闭原则”, 然而在添加其抽象产品时,确不支持“开—闭”原则。抽象工厂模式以一种倾斜的 方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的产品等级 结构的增加提供这样的方便。

【抽象工厂模式与其它模式】
单例模式(singleton模式):具体工厂类可以设计成单例类,由于工厂通常有一个就可以,因此具体工厂子类一般都实现为一个Singleton。
工厂方法模式(factory method模式):抽象工厂创建产品的方法定义为工厂方法。
原型模式(prototype模式):如果有多个可能的产品系列,具体的工厂也可以使用原型模式,具体工厂使用产品系列中
每一个产品的原型进行实例化并且通过复制它的原型来创建新的产品。

【抽象工厂模式PHP示例】

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
 
<?php
/**
 * 抽象工厂模式 2010-05-28 sz
 * @author phppan.p#gmail.com  
 * http://www.phppan.com 哥学社成员(http://www.blog-brother.com/)
 * @package design pattern
 */
 
/**
 * 抽象工厂
 */
interface AbstractFactory {
    /**
     * 创建等级结构为A的产品的工厂方法
     */
    public function createProductA();
 
     /**
     * 创建等级结构为B的产品的工厂方法
     */
    public function createProductB();
 
}
 
/**
 * 具体工厂1
 */
class ConcreteFactory1 implements AbstractFactory{
 
    public function createProductA() {
        return new ProductA1();
    }
 
    public function createProductB() {
        return new ProductB1();
    }
}
 
 
/**
 * 具体工厂2
 */
class ConcreteFactory2 implements AbstractFactory{
 
    public function createProductA() {
        return new ProductA2();
    }
 
    public function createProductB() {
        return new ProductB2();
    }
}
 
/**
 * 抽象产品A
 */
interface AbstractProductA {
 
    /**
     * 取得产品名
     */
    public function getName();
}
 
/**
 * 抽象产品B
 */
interface AbstractProductB {
 
    /**
     * 取得产品名
     */
    public function getName();
}
 
/**
 * 具体产品A1
 */
class ProductA1 implements AbstractProductA {
    private $_name;
 
    public function __construct() {
        $this->_name = 'product A1';
    }
 
    public function getName() {
        return $this->_name;
    }
}
 
 
/**
 * 具体产品A2
 */
class ProductA2 implements AbstractProductA {
    private $_name;
 
    public function __construct() {
        $this->_name = 'product A2';
    }
 
    public function getName() {
        return $this->_name;
    }
}
 
 
/**
 * 具体产品B1
 */
class ProductB1 implements AbstractProductB {
    private $_name;
 
    public function __construct() {
        $this->_name = 'product B1';
    }
 
    public function getName() {
        return $this->_name;
    }
}
 
/**
 * 具体产品B2
 */
class ProductB2 implements AbstractProductB {
    private $_name;
 
    public function __construct() {
        $this->_name = 'product B2';
    }
 
    public function getName() {
        return $this->_name;
    }
}
 
 
/**
 * 客户端
 */
class Client {
 
     /**
     * Main program.
     */
    public static function main() {
        self::run(new ConcreteFactory1());
        self::run(new ConcreteFactory2());
    }
 
    /**
     * 调用工厂实例生成产品,输出产品名
     * @param   $factory    AbstractFactory     工厂实例
     */
    public static function run(AbstractFactory $factory) {
        $productA = $factory->createProductA();
        $productB = $factory->createProductB();
        echo $productA->getName(), '<br />';
        echo $productB->getName(), '<br />';
    }
 
}
 
Client::main();
?>