`
xieye
  • 浏览: 835496 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

php设计模式-装饰器示例详细解析

    博客分类:
  • PHP
阅读更多
学习用。

本装饰器设计模式的示例改自《设计模式 - Java语言中的应用》结城 浩著  page 156 - 163
总共6个文件,
一个客户调用示例Main.php
一个顶层抽象类 Display.php
一个直接继承Display的子类,也是最中间的类StringDisplay
一个继承自顶层抽象类的抽象类Border,代表所有外框类
一个继承自Border的边框外框类SideBorder
一个继承自Border的完整外框类FullBorder
类名与文件名无必然关系,当然相同便于理解
附件可下载所有的类。

Main类
<?php
    require_once('Display.php');
    require_once('StringDisplay.php');
    require_once('Border.php');
    require_once('SideBorder.php');
    require_once('FullBorder.php');
    
    /**
     * php装饰器设计模式的客户端示例,目的:显示打印字符的装饰功能。会在浏览器输出字符串,被层层包裹
     * 
     * 本设计模式的示例改自《设计模式 - Java语言中的应用》结城 浩著  page 156 - 163
     * 
     * 读者机器的条件:php5,某个服务器如apache,
     *             将几个程序放到服务器文档根目录下,
     *             访问http://127.0.0.1/Main.php即可看到效果
     */
    class TestDecorator
    {
        public static function main() 
        {
            //打印“Hello,world”,没有任何装饰
            $b1 = new StringDisplay('Hello, world.');
            //把装饰字符'#'加在b1的左右两边
            $b2 = new SideBorder($b1, '#');
            //把b2加上装饰外框
            $b3 = new FullBorder($b2);
            
            //b4在核心的外面加上了多重外框
            $b4 = 
                new SideBorder(
                    new FullBorder(
                        new FullBorder(
                            new SideBorder(
                                new FullBorder(
                                    new StringDisplay('Hello, world.')
                                ), '*'
                            )
                        )
                    ), '/'
                );
            $b1->show();
            $b2->show();
            $b3->show();
            $b4->show();
        }
    }

    TestDecorator::main();
        
?>



Display类
<?php
    /**
     * 位于最顶层,表示了整个设计模式示例的功能:打印字符串
     */
    abstract class Display
    {
        public abstract function getColumns();    //取得横向的字数,把责任委托给子类,所以抽象,下同
                                                  //观察子类可知,只要有一个类使用到了,
                                                  //需要所有的类都要有这个方法!
                                                  
        public abstract function getRows();       //取得纵向的行数,把责任委托给子类
        public abstract function getRowText($row);//取得第row行的字符串
        
        public function show()                    //因为这个方法的实现是固定的,所以写这里
        {
            for ($i = 0; $i < $this->getRows(); $i++) {
                echo $this->getRowText($i) . "<br />";
            }
        }
    }
?>



StringDidplay类
<?php
    /**
     * 注意此类一定被包裹在核心,和别的类不同,虽然都是继承Display类
     *
     */
    class StringDisplay extends Display
    {
        private $string;                     //最里面的,一定会被打印出的字符串
        
        public function __construct($string) //需要在外部指定
        {
            $this->string = $string;
        }
        
        public function getColumns()         //注意!,仅被某类调用,却写到每个类中!!
        {
            return strlen($this->string);
        }
        
        public function getRows()            //核心只打印一行
        {
            return 1;
        }
        
        
        public  function getRowText($row)    //仅在row为0时才返回
        {
            if ($row == 0) {
                return $this->string;
            } else {
                return null;
            }
        }
        
    }
    
?>



Border类
<?php

    /**
     * 因为外框又有多种,所以把共性抽取出来,形成此抽象类,其中,
     * 还确定了每个装饰器子类都有的构造方法和属性,通常就是属于共同接口的对象
     */
    abstract class Border extends Display
    {
        protected $display;                             //注意到:是同一接口的对象,php
                                                        //不像java能表达出类型,但实际是的
        
        protected function __construct(Display $display)//后面可看到,子类实际可以扩展构造方法
        {
            $this->display = $display;
        }
    }
        
?>



SideBorder类
<?php

    /**
     * 在字符两边输出特定字符(由程序外部指定)的外框类,
     * 通过Border间接继承Display
     *
     */
    class SideBorder extends Border
    {
        private $borderChar;                              //装饰用的字符,会写到两边
        
        public function __construct(Display $display, $ch)//注意重写了构造方法。
        {
            parent::__construct($display);
            $this->borderChar = $ch;
        }
        
        public function getColumns() 
        {
            return 1+ $this->display->getColumns() + 1;
        }
        
        public function getRows() 
        {
            return $this->display->getRows();
        }
        
        /**
         * 最后的显示效果如 |hello, world|
         * 其中两边的|只是示例,由外部传入的。
         * 根据php的类型,没有字符类,所以请确保只传入一个字符。这里没有判断,也可以抛异常等。
         */
        public function getRowText($row) 
        {
            return $this->borderChar . $this->display->getRowText($row) . $this->borderChar;
        }
    }
        
?>



FullBorder类
<?php

    /**
     * 把字符包裹于其中的外框类
     * 通过Border间接继承Display
     *
     */
    class FullBorder extends Border
    {
        private $borderChar;
        
        public function __construct(Display $display)
        {
            parent::__construct($display);
        }
        
        public function getColumns()            //这些方法很重要,保证了上下的字符对齐(假定字符宽度相等)
                                                //注意到:虽然别的类的该方法似乎没有用到,
                                                //实际在这里用到了,让本类可以知道里面内核的字符宽度 
        {
            return 1 + $this->display->getColumns() + 1;
        }
        
        public function getRows() 
        {
            return 1 + $this->display->getRows() + 1;
        }
        
        /**
         * 把行数确定为核心内容加2后,见上getRows,就可以在顶部和底部输出装饰
         * +-------------------+
         * +-------------------+
         * 
         * 然后,在内容的两边输出 | 字符
         */
        public function getRowText($row) 
        {
            if ($row == 0) {
                return '+' . $this->makeLine('-', $this->display->getColumns()) . '+';
            } elseif ($row == $this->display->getRows() + 1) {
                return '+' . $this->makeLine('-', $this->display->getColumns()) . '+';
            } else {
                return '|' . $this->display->getRowText($row - 1) . '|';
            }
        }
        
        private function makeLine($ch, $count) 
        {
            $s = '';
            for ($i = 0; $i < $count; $i++) {
                $s .= $ch;
            }
            return $s;
        }
        
    }

?>



运行效果图o-m-g


  • 大小: 62.2 KB
分享到:
评论
6 楼 chrisyue 2010-03-11  
xieye 写道
讲类不直观,讲对象更加直观一些。

一个装饰器对象,他里面有一个装饰器成员,而这个成员本身是对象,里面又有一个成员,如此类推,可以很深。


当最外部对象执行某方法时,会调用其成员的方法,而其中又会调用其里面成员的方法,当然这都要看函数具体的写法!不过示例中的例子是一直调用到了核心子类的方法。

注意到,为了强制所有子类都实现,在顶层抽象类中,故意把这些方法都定义成了抽象方法,这就是原因,作者怕把自己也搞迷糊,所以让编译器来替我们检查(忘了写会页面报错),而方法就是在顶层类中定义抽象方法。

这样讲大家就明白了。^_^

没错,其实我觉得说模式就是为了表达一种思路,其实只要用点使用例子把思路表达到位了,class怎么写其实读者自己也能想出来
5 楼 xieye 2010-02-02  
simon4545 写道
此贴只推荐技术交流,切莫用于实际项目中


我对模式的理解就是逻辑复杂了,需要把复杂逻辑散布在各个小文件中,而且是用OO的模式。
4 楼 simon4545 2010-02-02  
此贴只推荐技术交流,切莫用于实际项目中
3 楼 ajonjun 2010-01-19  
谢谢,通俗易懂
2 楼 ymdf 2010-01-16  
楼主有没其他设计模式的详细解析啊,感觉这方面资料实在太少了
1 楼 xieye 2009-09-13  
讲类不直观,讲对象更加直观一些。

一个装饰器对象,他里面有一个装饰器成员,而这个成员本身是对象,里面又有一个成员,如此类推,可以很深。


当最外部对象执行某方法时,会调用其成员的方法,而其中又会调用其里面成员的方法,当然这都要看函数具体的写法!不过示例中的例子是一直调用到了核心子类的方法。

注意到,为了强制所有子类都实现,在顶层抽象类中,故意把这些方法都定义成了抽象方法,这就是原因,作者怕把自己也搞迷糊,所以让编译器来替我们检查(忘了写会页面报错),而方法就是在顶层类中定义抽象方法。

这样讲大家就明白了。^_^

相关推荐

    编程之道-IOS设计模式解析[www.xiandoudou.com]

    书中详细介绍了多种iOS设计模式,包括单例模式、工厂模式、建造者模式、代理模式、装饰器模式、观察者模式、策略模式、状态模式、模版方法模式和访问者模式。每个模式都配有实际的Objective-C代码示例,帮助读者理解...

    PHP简单装饰器模式实现与用法示例

    7. PHP中面向对象编程的其他设计模式和技巧:文中提到了多种面向对象的PHP设计模式和技巧,比如《php面向对象程序设计入门教程》、《PHP基本语法入门教程》等,这些都是学习PHP编程的宝贵资源。 通过对本文的知识点...

    设计模式总结笔记设计模式总结笔记

    ### 设计模式总结笔记 #### 一、概述 设计模式是一种在特定上下文中解决软件设计问题的方案。它并不是一种现成的代码片段或者框架,而是一种指导思想,帮助开发者理解如何更好地组织代码来解决问题。设计模式可以...

    PHP_设计模式.rar

    这个网站可能包含更多的书籍、教程、代码示例和社区支持,对深入学习和交流PHP设计模式非常有帮助。 总的来说,通过学习《PHP设计模式》,开发者能够理解并应用这些模式,提高代码质量,增强代码的可读性和可维护性...

    PHP面向对象程序设计组合模式与装饰模式详解共6页.pdf

    - **组件(Component)**: 定义一个接口,被装饰者和装饰器共同实现。 - **装饰者(Decorator)**: 继承组件接口,包含一个指向组件对象的引用,并可以添加额外的功能。 - **具体装饰者(Concrete Decorator)**:...

    design-patterns:PHP 中的设计模式示例

    本项目名为“design-patterns:PHP中的设计模式示例”,显然是一个用于展示和学习PHP设计模式的资源库。 在PHP中,常见的设计模式可以分为三类:创建型模式、结构型模式和行为型模式。这些模式帮助开发者在面对复杂...

    23种设计模式(中文、全).rar

    下面,我们将详细探讨这23种设计模式。 1. **单例模式**:确保一个类只有一个实例,并提供全局访问点。在多线程环境下,单例模式能有效控制资源的使用。 2. **工厂方法模式**:定义一个用于创建对象的接口,让子类...

    PHP设计模式之迭代器模式的深入解析

    迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。PHP作为一门面向对象的编程语言,其标准库(SPL)中就内置了对迭代器模式...

    php-classes-源码.rar

    PHP常见的设计模式有单例模式、工厂模式、装饰器模式、观察者模式等,这些模式在类库源码中经常被应用,有助于我们构建更稳定、可维护的代码。 在PHP类库中,错误处理是不可或缺的一部分。通常,源码会包含异常处理...

    深入PHP:面向对象、模式与实践(第三版)高清PDF和完整源码_(0601).rar

    书中涵盖了多种设计模式,如工厂模式、单例模式、观察者模式、装饰器模式、策略模式等。这些模式可以帮助开发者写出灵活、可扩展的代码,并降低代码间的耦合度。 3. 实践与最佳实践: 除了理论知识,书籍还强调...

    patterns-cheat-sheet:PHP OOP(Laravel)中的设计模式实现示例

    **PHP OOP与Laravel设计模式实践指南** 在软件开发中,设计模式是解决常见问题的最佳实践和模板,尤其在面向对象编程(OOP)中,它们为代码组织和复用提供了强大的指导。PHP作为流行的服务器端脚本语言,与Laravel...

    PHP设计模式之调解者模式的深入解析

    调解者模式(Mediator Pattern)是一种行为型设计模式,旨在通过引入一个中间组件——调解者,来减少一系列对象之间的通信复杂度。这种模式允许对象之间通过一个中央点进行交互,从而使得这些对象之间不会直接相互...

    sitemesh布局知识点汇总

    - **动态选择装饰器**:Sitemesh允许根据特定条件动态选择装饰器,实现更加个性化的布局设计。 - **属性体系**:Sitemesh提供了一套功能丰富的属性体系,支持构建更为复杂和灵活的装饰器,而Struts Tiles在这方面的...

    php-poo:练习一些遵循SOLID原则PHP POO

    8. **面向对象设计模式**:SOLID原则通常与设计模式结合使用,如工厂模式、单例模式、观察者模式、装饰器模式等,这些模式在项目中可能有所体现。 9. **PHP的类和对象**:包括类的定义、构造函数、析构函数、属性和...

    ZendFramework1.0 PDF开发中-Nesting level too deep的解决

    3. **利用设计模式**:使用策略、工厂或装饰者等设计模式,可以使代码更易于理解和维护,同时减少不必要的嵌套。 4. **检查数据流**:确保在处理数据时没有形成循环引用或无限循环。例如,在遍历数组或数据库记录时...

    ZendFramework-1.7.2帮助文档

    Zend Framework 遵循 Model-View-Controller(MVC)设计模式,提倡“干干净净的代码”原则,使开发者能够快速构建健壮的 Web 应用。它提供了许多组件,如数据库抽象层、缓存、安全、表单处理、文件上传、邮件发送等...

    深入php面向对象、模式与实践

    以上知识点在实际开发中具有广泛应用,如在设计模式中,装饰模式、观察者模式和访问者模式都是基于面向对象特性实现的。装饰模式允许动态地给对象添加新的行为或职责;观察者模式用于实现对象间的发布/订阅机制;...

    2021-2022计算机二级等级考试试题及答案No.10364.docx

    15. 装饰设计模式允许动态地给一个对象添加一些额外的职责,装饰类持有被装饰对象的引用。 16. 在Windows 98中,直接拖动文件或目录到指定位置通常是复制或移动操作,而不是删除。 17. PowerPoint中,设置的项目...

    ZendFramework中文文档

    错误控制器示例 7.11. 使用传统的模块目录结构 7.11.1. 简介 7.11.2. 指定模块控制器目录 7.11.3. Routing to modules 7.11.4. 模块或全局缺省控制器 7.12. MVC 异常 7.12.1. 介绍 7.12.2. 如何处理异常? ...

Global site tag (gtag.js) - Google Analytics