PHP 23种设计模式介绍(二)---- 结构设计模式

适配器模式(Adapter)

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。

我们通过下面的实例来演示适配器模式的使用。其中,音频播放器设备只能播放 mp3 文件,通过使用一个更高级的音频播放器来播放 vlc 和 mp4 文件。

介绍

意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

主要解决:主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。

何时使用: 1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

如何解决:继承或依赖(推荐)。

关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。

应用实例: 1、美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。 2、JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。 3、在 LINUX 上运行 WINDOWS 程序。 4、JAVA 中的 jdbc。

优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。

缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

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

<?php

/**

 * 第一种方式:对象适配器

 */

interface Target {

    public function sampleMethod1();

    public function sampleMethod2();

}

class Adaptee {

    public function sampleMethod1() {

        echo '++++++++';

    }

}

class Adapter implements Target {

    private $_adaptee;

    public function __construct(Adaptee $adaptee) {

        $this->_adaptee = $adaptee;

    }

    public function sampleMethod1() {

        $this->_adaptee->sampleMethod1();

    }

    public function sampleMethod2() {

        echo '————————';

    }

}

$adapter new Adapter(new Adaptee());

$adapter->sampleMethod1();//输出:++++++++

$adapter->sampleMethod2();//输出:————————

/**

 * 第二种方式:类适配器

 */

interface Target2 {

    public function sampleMethod1();

    public function sampleMethod2();

}

class Adaptee2 { // 源角色

    public function sampleMethod1() {echo '++++++++';}

}

class Adapter2 extends Adaptee2 implements Target2 { // 适配后角色

    public function sampleMethod2() {echo '————————';}

}

$adapter new Adapter2();

$adapter->sampleMethod1();//输出:++++++++

$adapter->sampleMethod2();//输出:————————

?>

桥接模式(Bridge)

桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

我们通过下面的实例来演示桥接模式(Bridge Pattern)的用法。其中,可以使用相同的抽象类方法但是不同的桥接实现类,来画出不同颜色的圆。

介绍

意图:将抽象部分与实现部分分离,使它们都可以独立的变化。

主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。

何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。

如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。

关键代码:抽象类依赖实现类。

应用实例: 1、猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选择。 2、墙上的开关,可以看到的开关是抽象的,不用管里面具体怎么实现的。

优点: 1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。

缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

使用场景: 1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

注意事项:对于两个独立变化的维度,使用桥接模式再适合不过了。

桥接与适配器模式的关系(适配器模式上面已讲解):
桥接属于聚合关系,两者关联 但不继承
适配器属于组合关系,适配者需要继承源

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

<?php

/**

 *

 *实现化角色, 给出实现化角色的接口,但不给出具体的实现。

 */

abstract class Implementor {

    abstract public function operationImp();

}

class ConcreteImplementorA extends Implementor { // 具体化角色A

    public function operationImp() {echo "A";}

}

class ConcreteImplementorB extends Implementor { // 具体化角色B

    public function operationImp() {echo "B";}

}

/**

 *

 * 抽象化角色,抽象化给出的定义,并保存一个对实现化对象的引用

 */

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() { $this->imp->operationImp(); }

}

// client

$abstraction new RefinedAbstraction(new ConcreteImplementorA());

$abstraction->operation();//输出:A

$abstraction new RefinedAbstraction(new ConcreteImplementorB());

$abstraction->operation();//输出:B

?>

组合模式(Composite)

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

我们通过下面的实例来演示组合模式的用法。实例演示了一个组织中员工的层次结构。

介绍

意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。

关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。

应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。

优点: 1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

注意事项:定义时为具体类。

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

<?php

/**

 *

 *安全式合成模式

 */

interface Component {

    public function getComposite(); //返回自己的实例

    public function operation();

}

class Composite implements Component { // 树枝组件角色

    private $_composites;

    public function __construct() { $this->_composites = array(); }

    public function getComposite() { return $this; }

     public function operation() {

         foreach ($this->_composites as $composite) {

            $composite->operation();

        }

     }

    public function add(Component $component) {  //聚集管理方法 添加一个子对象

        $this->_composites[] = $component;

    }

    public function remove(Component $component) { // 聚集管理方法 删除一个子对象

        foreach ($this->_composites as $key => $row) {

            if ($component == $row) { unset($this->_composites[$key]); return TRUE; }

        }

        return FALSE;

    }

    public function getChild() { // 聚集管理方法 返回所有的子对象

       return $this->_composites;

    }

}

class Leaf implements Component {

    private $_name;

    public function __construct($name) { $this->_name = $name; }

    public function operation() {}

    public function getComposite() {return null;}

}

// client

$leaf1 new Leaf('first');

$leaf2 new Leaf('second');

$composite new Composite();

$composite->add($leaf1);

$composite->add($leaf2);

$composite->operation();

$composite->remove($leaf2);

$composite->operation();

/**

 *

 *透明式合成模式

 */

interface Component { // 抽象组件角色

    public function getComposite(); // 返回自己的实例

    public function operation(); // 示例方法

    public function add(Component $component); // 聚集管理方法,添加一个子对象

    public function remove(Component $component); // 聚集管理方法 删除一个子对象

    public function getChild(); // 聚集管理方法 返回所有的子对象

}

class Composite implements Component { // 树枝组件角色

    private $_composites;

    public function __construct() { $this->_composites = array(); }

    public function getComposite() { return $this; }

    public function operation() { // 示例方法,调用各个子对象的operation方法

        foreach ($this->_composites as $composite) {

            $composite->operation();

        }

    }

    public function add(Component $component) { // 聚集管理方法 添加一个子对象

        $this->_composites[] = $component;

    }

    public function remove(Component $component) { // 聚集管理方法 删除一个子对象

        foreach ($this->_composites as $key => $row) {

            if ($component == $row) { unset($this->_composites[$key]); return TRUE; }

        }

        return FALSE;

    }

    public function getChild() { // 聚集管理方法 返回所有的子对象

       return $this->_composites;

    }

}

class Leaf implements Component {

    private $_name;

    public function __construct($name) {$this->_name = $name;}

    public function operation() {echo $this->_name."<br>";}

    public function getComposite() { return null; }

    public function add(Component $component) { return FALSE; }

    public function remove(Component $component) { return FALSE; }

    public function getChild() { return null; }

}

// client

$leaf1 new Leaf('first');

$leaf2 new Leaf('second');

$composite new Composite();

$composite->add($leaf1);

$composite->add($leaf2);

$composite->operation();

$composite->remove($leaf2);

$composite->operation();

?>

装饰器模式(Decorator)

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。

介绍

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

何时使用:在不想增加很多子类的情况下扩展类。

如何解决:将具体功能职责划分,同时继承装饰者模式。

关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。

应用实例: 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。

注意事项:可代替继承。

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

<?php

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();

    }

}

class ConcreteDecoratorA extends Decorator { // 具体装饰类A

    public function __construct(Component $component) {

        parent::__construct($component);

    }

    public function operation() {

        parent::operation();    //  调用装饰类的操作

        $this->addedOperationA();   //  新增加的操作

    }

    public function addedOperationA() {echo 'A加点酱油;';}

}

class ConcreteDecoratorB extends Decorator { // 具体装饰类B

    public function __construct(Component $component) {

        parent::__construct($component);

    }

    public function operation() {

        parent::operation();

        $this->addedOperationB();

    }

    public function addedOperationB() {echo "B加点辣椒;";}

}

class ConcreteComponent implements Component{ //具体组件类

    public function operation() {}

}

// clients

$component new ConcreteComponent();

$decoratorA new ConcreteDecoratorA($component);

$decoratorB new ConcreteDecoratorB($decoratorA);

$decoratorA->operation();//输出:A加点酱油;

echo '<br>--------<br>';

$decoratorB->operation();//输出:A加点酱油;B加点辣椒;

?>

外观模式(Facade)

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。

这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

介绍

意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。

何时使用: 1、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。 2、定义系统的入口。

如何解决:客户端不与系统耦合,外观类与系统耦合。

关键代码:在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。

应用实例: 1、去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。 2、JAVA 的三层开发模式。

优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

使用场景: 1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险。

注意事项:在层次化结构中,可以使用外观模式定义系统中每一层的入口。

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

<?php

class Camera {

    public function turnOn() {}

    public function turnOff() {}

    public function rotate($degrees) {}

}

class Light {

    public function turnOn() {}

    public function turnOff() {}

    public function changeBulb() {}

}

class Sensor {

    public function activate() {}

    public function deactivate() {}

    public function trigger() {}

}

class Alarm {

    public function activate() {}

    public function deactivate() {}

    public function ring() {}

    public function stopRing() {}

}

class SecurityFacade {

    private $_camera1$_camera2;

    private $_light1$_light2$_light3;

    private $_sensor;

    private $_alarm;

    public function __construct() {

        $this->_camera1 = new Camera();

        $this->_camera2 = new Camera();

        $this->_light1 = new Light();

        $this->_light2 = new Light();

        $this->_light3 = new Light();

        $this->_sensor = new Sensor();

        $this->_alarm = new Alarm();

    }

    public function activate() {

        $this->_camera1->turnOn();

        $this->_camera2->turnOn();

        $this->_light1->turnOn();

        $this->_light2->turnOn();

        $this->_light3->turnOn();

        $this->_sensor->activate();

        $this->_alarm->activate();

    }

    public  function deactivate() {

        $this->_camera1->turnOff();

        $this->_camera2->turnOff();

        $this->_light1->turnOff();

        $this->_light2->turnOff();

        $this->_light3->turnOff();

        $this->_sensor->deactivate();

        $this->_alarm->deactivate();

    }

}

//client

$security new SecurityFacade();

$security->activate();

?>

代理模式(Proxy)

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

介绍

意图:为其他对象提供一种代理以控制对这个对象的访问。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层,并且可以在不改变目标对象的情况下添加一些额外的功能。

何时使用:想在访问一个类时做一些控制。

如何解决:增加中间层。

关键代码:实现与被代理类组合。

应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

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

<?

abstract class Subject { // 抽象主题角色

    abstract public function action();

}

class RealSubject extends Subject { // 真实主题角色

    public function __construct() {}

    public function action() {}

}

class ProxySubject extends Subject { // 代理主题角色

    private $_real_subject = NULL;

    public function __construct() {}

    public function action() {

        $this->_beforeAction();

        if (is_null($this->_real_subject)) {

            $this->_real_subject = new RealSubject();

        }

        $this->_real_subject->action();

        $this->_afterAction();

    }

    private function _beforeAction() {

        echo '在action前,我想干点啥....';

    }

    private function _afterAction() {

         echo '在action后,我还想干点啥....';

    }

}

// client

$subject new ProxySubject();

$subject->action();//输出:在action前,我想干点啥....在action后,我还想干点啥....

?>

享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。

介绍

意图:运用共享技术有效地支持大量细粒度的对象。

主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

关键代码:用 HashMap 存储这些对象。

应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。

注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。

享元模式中主要角色:

抽象享元(Flyweight)角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。那些需要外运状态的操作可以通过调用商业以参数形式传入

具体享元(ConcreteFlyweight)角色:实现Flyweight接口,并为内部状态(如果有的话)拉回存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的

不共享的具体享元(UnsharedConcreteFlyweight)角色:并非所有的Flyweight子类都需要被共享。Flyweigth使共享成为可能,但它并不强制共享

享元工厂(FlyweightFactory)角色:负责创建和管理享元角色。本角色必须保证享元对象可能被系统适当地共享

客户端(Client)角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外部状态

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

<?php

/***

 * 享元模式

 * Class Flyweight

 */

abstract class Resources{

    public $resource=null;

    abstract public function operate();

}

class unShareFlyWeight extends Resources{

    public function __construct($resource_str) {

        $this->resource = $resource_str;

    }

    public function operate(){

        echo $this->resource."<br>";

    }

}

class shareFlyWeight extends Resources{

    private $resources array();

    public function get_resource($resource_str){

        if(isset($this->resources[$resource_str])) {

            return $this->resources[$resource_str];

        }else {

            return $this->resources[$resource_str] = $resource_str;

        }

    }

    public function operate(){

        foreach ($this->resources as $key => $resources) {

            echo $key.":".$resources."<br>";

        }

    }

}

// client

$flyweight new shareFlyWeight();

$flyweight->get_resource('a');

$flyweight->operate();

$flyweight->get_resource('b');

$flyweight->operate();

$flyweight->get_resource('c');

$flyweight->operate();

// 不共享的对象,单独调用

$uflyweight new unShareFlyWeight('A');

$uflyweight->operate();

$uflyweight new unShareFlyWeight('B');

$uflyweight->operate();

//结果

//a:a

//a:a

//b:b

//a:a

//b:b

//c:c

//A

//B

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值