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
php设计模式-装饰器示例详细解析_第1张图片

你可能感兴趣的:(设计模式,PHP,应用服务器,浏览器,OO)