zoukankan      html  css  js  c++  java
  • PHP设计模式—组合模式

    定义:

    组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑用组合模式了。

     

    实现方式:

    1、透明方式:叶节点和枝节点对于外界没有什么区别,它们具备完全一致的行为接口,问题则是叶节点会有冗余方法。

    2、安全方式:叶节点中的冗余代码不实现,问题则是由于不够透明,所以叶节点和枝节点将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。

    代码实例:

    一、透明方式实现:

    // 1、抽象类Component.php
    /**
     * 包含叶节点和枝节点方法的抽象类
     * Class Component
     */
    abstract class Component
    {
        /**
         * @var
         */
        protected $name;
    
        /**
         * Component constructor.
         * @param $name
         */
        public function __construct($name)
        {
            $this->name = $name;
        }
    
    
        /**
         * 添加叶节点或枝节点
         * @param Component $component
         * @return mixed
         */
        abstract public function add(Component $component);
    
    
        /**
         * @param $depth
         * @return mixed
         */
        abstract public function display($depth);
    }
    
    
    // 2、枝节点Composite.php
    /**
     * 枝节点
     * Class Composite
     */
    class Composite extends Component
    {
        /**
         * @var array
         */
        protected $children = [];
    
        /**
         * @param Component $component
         * @return mixed|void
         */
        public function add(Component $component)
        {
            // TODO: Implement add() method.
            $this->children[] = $component;
        }
    
        public function display($depth)
        {
            // TODO: Implement display() method.
            $nameStr = str_repeat('-', $depth) . $this->name . '<br>';
            foreach ($this->children as $component) {
                $nameStr .= $component->display($depth + 2);
            }
            return $nameStr;
        }
    }
    
    
    // 3、叶节点Leaf.php
    /**
     * 叶节点
     * Class Leaf
     */
    class Leaf extends Component
    {
        /**
         * 叶节点不需要添加子节点,但为了保持叶节点和枝节点一致,代码冗余,透明方式
         * @param Component $component
         * @return mixed|string
         */
        public function add(Component $component)
        {
            // TODO: Implement add() method.
            return '叶节点不能添加子节点' . '<br>';
        }
    
        public function display($depth)
        {
            // TODO: Implement display() method.
            return str_repeat('-', $depth) . $this->name . '<br>';
        }
    }

    调用:

    // 生成树根root,根上长出两叶LeafA和LeafB
    $root = new Composite("root");
    $root->add(new Leaf("Leaf A"));
    $root->add(new Leaf("Leaf B"));
    
    // 根上长出分支 CompositeX,分支上也有两叶LeafXA和LeafXB
    $comp = new Composite("Composite X");
    $comp->add(new Leaf("Leaf XA"));
    $comp->add(new Leaf("Leaf XB"));
    $root->add($comp);
    
    // 在CompositeX分支上再长出分支CompositeXY,分支上也有两叶LeafXYA和LeafXYB
    $comp2 = new Composite("Composite XY");
    $comp2->add(new Leaf("Leaf XYA"));
    $comp2->add(new Leaf("Leaf XYB"));
    $comp->add($comp2);
    
    echo $root->display(2);

    结果:

    --root
    ----Leaf A
    ----Leaf B
    ----Composite X
    ------Leaf XA
    ------Leaf XB
    ------Composite XY
    --------Leaf XYA
    --------Leaf XYB

    二、安全方式实现:

    // 1、抽象类Component.php
    /**
     * 包含叶节点和枝节点方法的抽象类
     * Class Component
     */
    abstract class Component
    {
        /**
         * @var
         */
        protected $name;
    
        /**
         * Component constructor.
         * @param $name
         */
        public function __construct($name)
        {
            $this->name = $name;
        }
    
    
        /**
         * @param $depth
         * @return mixed
         */
        abstract public function display($depth);
    }
    
    
    // 2、枝节点Composite.php
    /**
     * 枝节点
     * Class Composite
     */
    class Composite extends Component
    {
        /**
         * @var array
         */
        protected $children = [];
    
        /**
         * @param Component $component
         * @return mixed|void
         */
        public function add(Component $component)
        {
            // TODO: Implement add() method.
            $this->children[] = $component;
        }
    
        public function display($depth)
        {
            // TODO: Implement display() method.
            $nameStr = str_repeat('-', $depth) . $this->name . '<br>';
            foreach ($this->children as $component) {
                $nameStr .= $component->display($depth + 2);
            }
            return $nameStr;
        }
    }
    
    
    // 3、叶节点Leaf.php
    /**
     * 叶节点
     * Class Leaf
     */
    class Leaf extends Component
    {
        public function display($depth)
        {
            // TODO: Implement display() method.
            return str_repeat('-', $depth) . $this->name . '<br>';
        }
    }

    调用:

    // 生成树根root,根上长出两叶LeafA和LeafB
    $root = new Composite("root");
    $root->add(new Leaf("Leaf A"));
    $root->add(new Leaf("Leaf B"));
    
    // 根上长出分支 CompositeX,分支上也有两叶LeafXA和LeafXB
    $comp = new Composite("Composite X");
    $comp->add(new Leaf("Leaf XA"));
    $comp->add(new Leaf("Leaf XB"));
    $root->add($comp);
    
    // 在CompositeX分支上再长出分支CompositeXY,分支上也有两叶LeafXYA和LeafXYB
    $comp2 = new Composite("Composite XY");
    $comp2->add(new Leaf("Leaf XYA"));
    $comp2->add(new Leaf("Leaf XYB"));
    $comp->add($comp2);
    
    echo $root->display(2);

    结果:

    --root
    ----Leaf A
    ----Leaf B
    ----Composite X
    ------Leaf XA
    ------Leaf XB
    ------Composite XY
    --------Leaf XYA
    --------Leaf XYB
  • 相关阅读:
    Redis连接池的介绍和原理
    Golang操作第三方开源Redis库
    Redis的五大数据类型和CRUD操作
    Redis的基本使用
    Redis数据库的基本介绍和安装
    Golang基于TCP协议实现简单的server和client聊天
    Golang反射中的Type和Kind的区别
    Golang中的常量
    Golang对基本数据类型和结构体进行反射
    Vue 使用lodash库减少watch对后台请求压力
  • 原文地址:https://www.cnblogs.com/woods1815/p/12822057.html
Copyright © 2011-2022 走看看