php设计模式(二):结构模式

上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式。

一、什么是结构型模式?

结构型模式是解析类和对象的内部结构和外部组合,通过优化程序结构解决模块之间的耦合问题。

二、结构型模式的种类:
    适配器模式
    桥接模式
   
装饰模式
    组合模式
    外观模式
    享元模式
 
  代理模式

1、 适配器模式(Adapter)

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

应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。

代码实现


<?php
/**
* 优才网公开课示例代码
*
* 适配器模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/

//老的代码
class User {
private $name;
function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}

//新代码,开放平台标准接口
interface UserInterface {
function getUserName();
}
class UserInfo implements UserInterface {
protected $user;
function __construct($user) {
$this->user = $user;
}
public function getUserName() {
return $this->user->getName();
}
}

$olduser = new User(‘张三‘);
echo $olduser->getName()."n";
$newuser = new UserInfo($olduser);
echo $newuser->getUserName()."n";

?>

注意点:这里的新接口使用了组合方式,UserInfo内部有一个成员变量保存老接口User对象,模块之间是松耦合的,这种结构其实就是组合模式。不要使用继承,虽然UserInfo继承User也能达到同样的目的,但是耦合度高,相互产生影响。

2、 桥接模式

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

特点:独立存在,扩展性强

应用:需要不断更换调用对象却执行相同的调用方法,实现扩展功能

代码实现


<?php
/**
* 优才网公开课示例代码
*
* 桥接模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/

abstract class Person {
abstract function getJob();
}

class Student extends Person {
public function getJob() {
return ‘学生‘;
}
}

class Teacher extends Person {
public function getJob() {
return ‘老师‘;
}
}

class BridgeObj {
protected $_person;

public function setPerson($person) {
$this->_person = $person;
}

public function getJob() {
return $this->_person->getJob();
}
}

$obj = new BridgeObj();
$obj->setPerson(new Student());
printf("本次桥接对象:%sn", $obj->getJob());
$obj->setPerson(new Teacher());
printf("本次桥接对象:%sn", $obj->getJob());

?>

3、 装饰模式

动态地给一个对象添加额外的职责。在原有的基础上进行功能增强。

特点:用来增强原有对象功能,依附于原有对象。

应用:用于需要对原有对象增加功能而不是完全覆盖的时候

代码实现


<?php
/**
* 优才网公开课示例代码
*
* 装饰模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/

//产品
abstract class Person {
abstract function getPermission();
}
//被装饰者
class User extends Person {
public function getPermission() {
return ‘公开文档‘;
}
}
//装饰类
class PermUser extends Person {
protected $_user;
protected $_special = ‘‘;
function __construct($user) {
$this->_user = $user;
}
public function getPermission() {
return $this->_user->getPermission() . $this->_special;
}
}
//装饰类产品
class JavaUser extends PermUser {
protected $_special = ‘ java程序‘;
}
class CPlusUser extends PermUser {
protected $_special = ‘ c++程序‘;
}

$user = new User();
printf("permission:%sn", $user->getPermission());
$user = new JavaUser($user);
printf("permission:%sn", $user->getPermission());
$user = new CPlusUser($user);
printf("permission:%sn", $user->getPermission());

?>

大家想想装饰和继承的区别在哪?

如果是上面的例子,如果用继承,是CPlusUser继承JavaUser还是反过来呢?谁也不知道最终使用者需要哪一种。

在多层关系的情况下,装饰是和顺序无关并且随时增加装饰,而继承只能是特定的顺序,所以装饰模式会更加的灵活。

4、组合模式

将对象组合成树形结构表示“部分-整体”的层次结构。

特点:灵活性强

应用:对象的部分-整体的层次结构,模糊组合对象和简单对象处理问题

代码实现

?





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

<?php  

/**  

 * 优才网公开课示例代码  

 *  

 * 组合模式  

 *  

 * @author 优才网全栈工程师教研组  

 * @see http://www.ucai.cn

 */

         

//继承模式  

         

class UserBaseInfo {  

    private
$name;  

         

    function
__construct($name) {  

        $this->name = $name;  

    }  

    public
function getName() {  

        return
$this->name;  

    }  

}  

class User extends
UserBaseInfo {  

    private
$login = false;  

             

    public
function setLogin($islogin) {  

        $this->login = $islogin;  

    }  

    public
function isLogin() {  

        return
$this->login;  

    }  

}  

         

$user
= new User(‘张三‘);  

$user->setLogin(true);  

if ($user->isLogin()) {  

    echo
$user->getName()."已经登录了n";  

} else
{  

    echo
$user->getName()."还没有登录n";  

}  

         

         

//组合模式  

         

class LoginInfo {  

    protected
$user;  

    protected
$login = false;  

             

    public
function setLogin($user, $isLogin) {  

        $this->user = $user;  

        $this->login = $isLogin;  

    }  

    public
function isLogin() {  

        return
$this->login;  

    }  

}  

         

$user
= new User(‘张三‘);  

$login
= new LoginInfo();  

$login->setLogin($user, true);  

if ($login->isLogin()) {  

    echo
$user->getName()."已经登录了n";  

} else
{  

    echo
$user->getName()."还没有登录n";  

}  

         

//部分可以更换,用继承则不行  

class Admin {  

    protected
$level;  

    function
__construct($level) {  

        $this->level = $level;  

    }  

    function
getLevel() {  

        return
$this->level;  

    }  

}  

$admin
= new Admin(1);  

$login->setLogin($admin, true);  

if ($login->isLogin()) {  

    printf("级别为 %d 的管理员已经登录了n", $admin->getLevel());  

} else
{  

    printf("级别为 %d 的管理员还没有登录n", $admin->getLevel());  

}  

         

?>

上面的例子分别展示了使用继承和组合来处理新功能,在简单的情况下看似区别不大,但在项目后期越来越复杂的时候组合模式的优势就越来越明显了。

例如上面的登录信息,如果要增加登录次数、最后登录时间、登录ip等信息,登录本身就会变成一个比较复杂的对象。如果以后有新的需求比如好友信息、用户的访问信息等,再要继承的话,用户类就会变得非常庞大,难免各父类之间没有冲突的变量和方法,而外部访问用户类的众多方法也变得很费劲。采用组合模式后,一个类负责一个角色,功能区分非常明显,扩展方便。

5、 外观模式(门面模式)

为了系统中的一组接口提供一个一致的界面

特点:向上抽取,有共性

应用:内部接口众多,由统一的接口来调用

代码实现


<?php
/**
* 优才网公开课示例代码
*
* 外观模式,也叫门面模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/

class Operation {
public function testPlus() {
printf("plus: %sn", (1 + 2 == 3 ? ‘true‘ : ‘false‘));
}
public function testMinus() {
printf("minus: %sn", (3 - 2 == 2 ? ‘true‘ : ‘false‘));
}
public function testTimes() {
printf("times: %sn", (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();

?>

门面模式估计大家在实际代码中都已经使用到了,接口较多时把相似功能的接口封装成一个接口供外部调用,这就是门面模式。

6、 享元模式

运用共享技术有效地支持大量细粒度对象,采用一个共享来避免大量有相同内容对象的开销。这种开销中最直观的就是内存的损耗。

特点:高效性,共享性

应用:系统底层的设计。例如字符串的创建。如果两个字符串相同,则不会创建第二个字符串,而是第二个的引用直接指向第一个字符串。$str1=”abc”,$str2=”abc”.则内存存储中只会创建一个字符串“abc”而引用$str1.$str2都会指向它。

7、  代理模式

为其他对象提供一个代理来控制对这个对象的访问,就是给某一对象提供代理对象,并由代理对象控制具体对象的引用。能够协调调用者和被调用者,能够在一定程度上降低系统的耦合性。

特点:低耦合性,独立性好,安全性

应用:客户访问不到或者被访问者希望隐藏自己,所以通过代理来访问自己。

代码实现


<?php
/**
* 优才网公开课示例代码
*
* 代理模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/

//内部对象
class User {
public function getName() {
return ‘张三‘;
}
public function getType() {
return ‘付费用户‘;
}
}

//代理接口定义,例如开放平台
interface UserInterface {
function getName();
}
//代理对象
class UserProxy implements UserInterface {
protected $_user;
function __construct() {
$this->_user = new User();
}
public function getName() {
return $this->_user->getName();
}
}

//内部调用
$user = new User();
printf("user name:%sn", $user->getName());
printf("user type:%sn", $user->getType());
//外部调用
// $user = new UserProxy();
// printf("user name:%sn", $user->getName());
// printf("user type:%sn", $user->getType()); //不能访问,及时知道内部对象有这个方法

?>

三、总结

1、代理模式、适配器模式、门面模式、装饰模式的区别

a、
相同之处:都封装一个内部对象,调用内部对象的方法

b、
不同之处:各自有各自的特性和应用场景,不能相互替代。所以用的时候要仔细分析用那种合适。

2、 关于模式的选用问题

模式的选用要根据实际的业务需求,通过对业务逻辑的仔细分析,再根据模式具有的特性和应用场景进行合理的选择和区分。大部分情况下业务的场景决定了哪种模式,而不是选择哪个模式去实现一个业务,少数情况几种模式确实都能解决问题,那主要就是考虑以后的扩展了。

到这里我们已经了解了7种结构型模式,下一篇我们继续给大家介绍设计模式的行为型模式,先预览一下行为型模式的种类吧:

模版方法模式

命令模式

迭代器模式

观察者模式

终结者模式

备忘录模式

解释器模式

状态模式

策略模式

职责链模式

访问者模式

视频地址:http://www.ucai.cn/opencourse/98?f=10

时间: 2024-10-26 12:20:28

php设计模式(二):结构模式的相关文章

设计模式-之结构模式

一:结构型模式总结全图: 二:详细解析: (Adapter)适配器模式图 Adapter适配器模式:创建一个接口去使用现成的不兼容的接口的类,主要应用是对系统维护添加新功能时. 使用过程:给要使用的对象提供一个访问接口,使得目标对象功能整合到系统中. 生活实例:简单典型的就是电脑笔记本电源 2. Proxy代理模式 Proxy代理模式:用代理对象来控制对原有对象的引用,其接口不可以改变. 3. Decorator装饰模式图     public class Test { public stati

设计模式之结构模式

1. 适配器模式 1)类的适配器模式 2)对象的适配器模式 3) 接口的适配器模式 接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行了. 2. 装饰模

设计模式:二

php面向对象设计模式中,工厂模式,从字面中就可以以理解为,工厂模式就是在不改变原来代码的结构的基础上,根据需求的增加类定义去完成 <?php header("Content-Type:text/html; charset=utf8"); /** * php设计模式 * 二:工厂模式 * */ // 定义接口DB类 interface DB{ function conn(); } class dbmysql implements DB{ public function conn(

设计模式大类--结构模式(上)

大概有7中结构模式,分为上下两篇.一.Adapter(适配器)描述:将两个不兼容的类结合一起使用,一般需要用到其中某个类的若干方法好处:在两个类直接创建一个混合接口,而不必修改类里面的其他代码 例子:假设我们要打桩,有两种类:方形桩 圆形桩.public class SquarePeg{ public void insert(String str){ System.out.println("SquarePeg insert():"+str); } } public class Roun

设计模式 ( 二十一 ):Vistor访问者模式 -- 行为型

1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同. 例子1:顾客在超市中将选择的商品,如苹果.图书等放在购物车中,然后到收银员处付款.在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车内顾客所选择的商品. 此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品

设计模式 ( 二十 ): Template method模板方法模式 -- 行为型

  1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1:银行业务办理流程在银行办理业务时,一般都包含几个基本固定步骤:取号排队->办理具体业务->对银行工作人员进行评分.取号取号排队和对银行工作人员进行评分业务逻辑是一样的.但是办理具体业务是个不相同的,具体业务可能取款.存款或者转账. 2.问题 如何保证架构逻辑的正常执行,而不被子类破坏 ? 3.

C#设计模式之十二代理模式(Proxy Pattern)【结构型】

原文:C#设计模式之十二代理模式(Proxy Pattern)[结构型] 一.引言 今天我们要讲[结构型]设计模式的第七个模式,也是"结构型"设计模式中的最后一个模式,该模式是[代理模式],英文名称是:Proxy Pattern.还是老套路,先从名字上来看看."代理"可以理解为"代替",代替"主人"做一些事情,为什么需要"代理",是因为某些原因(比如:安全方面的原因),不想让"主人"直接

[JAVA设计模式]第三部分:结构模式

声明:原创作品,转载时请注明文章来自SAP师太博客,并以超链接形式标明文章原始出处,否则将追究法律责任! 结构模式... 52 适配(Adapter)器模式... 52 类适配器模式结构... 52 对象适配器结构... 53 从Iterator到Enumeration的适配... 54 从Enumeration到Iterator的适配... 54 缺省适配(Default Adapter)器模式... 55 模式结构... 56 与适配器模式区别... 56 J2EE中的缺省适配模式... 5

C++设计模式之建造者模式(二)

3.省略指挥者Director的建造者模式 指挥者类Director在建造者模式中扮演非常重要的作用,简单的Director类用于指导具体建造者如何构建产品,它按一定次序调用Builder的buildPartX()方法,控制调用的先后次序,并向客户端返回一个完整的产品对象.Direcotr针对抽象的建造者进行编程,如果需要不同的建造者,只需把建造者传入指挥者类,无需修改之前的代码. 在有些情况下,为了简化系统结构,可以省略指挥者Director,指挥者不再指导产品的创建过程.而是在Builder

浅析JAVA设计模式之工厂模式(二)

1 工厂方法模式简介 工厂方法 (Factroy Method) 模式:又称多态性工厂模式(Polymorphic Factory),在这种模式中,核心工厂不再是一个具体的类,而是一个抽象工厂,提供具体工厂实现的接口,具体创建产品交由子工厂去做,抽象工厂不涉及任何产品被实例化的细节.而不同等级的产品,就对应一个不同等级的工厂,如下图. 图1 1.1工厂方法模式(多态性工厂模式): 工厂方法模式有三个角色: 1. 抽象产品接口 2. 具体产品类 3. 抽象工厂接口 4.具体工厂类. 1.2工厂方法