更多优质内容
请关注公众号

面向对象和设计模式(十九)支持树形结构的组合模式——PHP语言实现-张柏沛IT博客

正文内容

面向对象和设计模式(十九)支持树形结构的组合模式——PHP语言实现

栏目:PHP 系列:面向对象与设计模式 发布时间:2023-05-03 10:47 浏览量:2117
本系列文章目录
展开/收起

一、组合模式概念

组合模式可以将一组对象组织成树形结构,以表示一种“部分 - 整体”的层次结构。因此,组合模式是一种用于树形结构数据的设计模式。组合模式跟之前讲的面向对象设计中的“组合关系(通过组合来组装两个类)”是两回事。


相比于前面说的几种设计模式,组合模式是一种用的比较少的模式,数据或者说业务对象必须能表示成树形结构才能用到组合模式,比如用来表示目录结构、部门子部门和员工、订单与下游采购单/出库单/入库单等这样的场景、产品一级二级三级分组等。


下面直接上例子,假设有个需求:设计一个类来表示文件系统中的目录,能方便地实现下面这些功能:

动态地添加、删除某个目录下的子目录或文件;

统计指定目录下的文件个数;

统计指定目录下的文件总大小。

<?php

class FileSystemNode {
    private $path;
    private $isFile;    // 是否为文件
    private $subNodes = [];     // 当前节点的子节点
    private $father;        // 当前节点的父节点
    private $fileNum ;      // 当前文件下的文件个数,包含自身
    private $fileSize;  // 当前文件大小,对于空目录而言为0
  
    public function __construct($path, $isFile) {
      $this->path = $path;
      $this->isFile = $isFile;
      $this->fileNum = 1;
      $this->fileSize = $this->isFile ? getFileSize($this->path) : 0;
    }
  
    protected function setFather(FileSystemNode $father){
        $this->father = $father;
        $this->refreshFather($this->countSizeOfFiles(), $this->countNumOfFiles());
    }

    protected function removeFather(){
        $this->refreshFather(-$this->countSizeOfFiles(), -$this->countNumOfFiles());
        $this->father = null;
    }

    // 更新父节点的文件数量和文件大小
    public function refreshFather($changeSize, $changeNum){
        if(!$this->father){
            return;
        }
        $this->father->setFileSize($this->father->countSizeOfFiles() + $changeSize);
        $this->father->setFileNum($this->father->countNumOfFiles() + $changeNum);

        $this->father->refreshFather($changeSize, $changeNum);  // 递归
    }

    public function setFileNum($num){
        $this->fileNum = $num;
    }

    public function setFileSize($size){
        $this->fileSize = $size;
    }

    public function countNumOfFiles() {
       return $this->isFile ? $this->fileNum : $this->fileNum-1;
    }
  
    public function countSizeOfFiles() {
      return $this->fileSize;
    }
  
    public function getPath() {
      return $this->path;
    }
  
    public function addSubNode(FileSystemNode $fileOrDir) {
      $this->subNodes[] = $fileOrDir;
      $fileOrDir->setFather($this);
    }
  
    public function removeSubNode(FileSystemNode $fileOrDir) {
        foreach($this->subNodes as $i => $subNode){
            if($subNode->getPath() == $fileOrDir->getPath()){
                unset($this->subNodes[$i]);
                $fileOrDir->removeFather();
                break;
            }
        }
    }
    
    // 遍历本目录下所有的文件路径(这里使用树的前序遍历)
    public function iterate(){
        echo $this->getPath() . "\n";
        foreach($this->subNodes as $subNode){
            $subNode->iterate();
        }
    }
  }


从上面的例子来看,只要满足以下条件就算符合组合模式:

1、类中包含一个数组属性,该数组中存放者多个和本类属于同一实例的其他实例,表示子节点。

2、类中的A方法需要委托子节点(或者父节点)调用子节点(或者父节点)的A方法,比如上述例子中的 iterate()方法。


组合模式的设计思路,与其说是一种设计模式,倒不如说是对业务场景的一种数据结构和算法的抽象。其中,数据可以表示成树这种数据结构,业务逻辑可以通过在树上的递归遍历算法来实现。

组合模式将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现


使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也比较局限,它并不是一种很常用的设计模式。




更多内容请关注微信公众号
zbpblog微信公众号

如果您需要转载,可以点击下方按钮可以进行复制粘贴;本站博客文章为原创,请转载时注明以下信息

张柏沛IT技术博客 > 面向对象和设计模式(十九)支持树形结构的组合模式——PHP语言实现

热门推荐
推荐新闻