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

上一篇咱们介绍了设计模式的特性而且详细讲解了4种建立型模式,建立型模式是负责如何产生对象实例的,如今咱们继续来给你们介绍结构型模式。

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

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

一、 适配器模式(Adapter)
将一个类的接口转换成客户但愿的另外一个接口,适配器模式使得本来的因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。
应用场景:老代码接口不适应新的接口需求,或者代码不少很乱不便于继续修改,或者使用第三方类库。

代码实现c++

<?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也能达到一样的目的,可是耦合度高,相互产生影响。设计模式

 二、 桥接模式安全

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

    特色:独立存在,扩展性强优化

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

    代码实现spa

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

三、 装饰模式设计

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

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

      应用:用于须要对原有对象增长功能而不是彻底覆盖的时候

      代码实现

<?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仍是反过来呢?谁也不知道最终使用者须要哪种。

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

四、组合模式

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

      特色:灵活性强

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

      代码实现

<?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等信息,登陆自己就会变成一个比较复杂的对象。若是之后有新的需求好比好友信息、用户的访问信息等,再要继承的话,用户类就会变得很是庞大,不免各父类之间没有冲突的变量和方法,而外部访问用户类的众多方法也变得很费劲。采用组合模式后,一个类负责一个角色,功能区分很是明显,扩展方便。

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

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

      特色:向上抽取,有共性

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

      代码实现    

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

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

 

 

 

 

 

六、 享元模式

 

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

 

      特色:高效性,共享性

 

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

 

 

 

七、  代理模式

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

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

      应用:客户访问不到或者被访问者但愿隐藏本身,因此经过代理来访问本身。

      代码实现

<?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()); //不能访问,及时知道内部对象有这个方法   
         
?>

3、总结

 

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

 

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

 

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

 

 

 

   二、 关于模式的选用问题

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

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

模版方法模式

命令模式

迭代器模式

观察者模式

终结者模式

备忘录模式

解释器模式

状态模式

策略模式

职责链模式

访问者模式

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

相关文章
相关标签/搜索