初识设计模式——组合模式

个人理解

定义:组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构(Copy的)。

理解:存在前提条件,只有满足以下两个条件,才建议使用组合模式(Composite Pattern)

  1. 一组相似的对象,说明对象的相似度需要在较高的情况下才可以使用

  2. 具有树形结构的特性,比如公司部门的管理,系统多级权限的管理等等。

主要解决:主要解决的是复杂元素内部处理,客户程序与元素的内部程序解耦的问题。

组成部分:组合模式一般由一个统一的类进行实现,外部进行调用。

案例分析

以公司部门为原型,设计一个统一管理的类。

由于公司内部存在不同的部门,各部门直接会存在子级的部门及成员,所以可做一个类,每个部门、成员都属于该类的一个对象,具体代码如下。

场景代码

为了保证例子更加的真实,这里使用mysql进行数据的存储,所以需要建立两张表,branch(部门表)、member(成员表),并增加若干条数据,表格式如下代码所示:

CREATE TABLE `branch` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '' COMMENT '部门名称',
  `parent_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上级部门ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
INSERT INTO `branch` VALUES ('1', '总公司', '0');
INSERT INTO `branch` VALUES ('2', '华北区分公司', '1');
INSERT INTO `branch` VALUES ('3', '东北区分公司', '1');
INSERT INTO `branch` VALUES ('4', '西北区分公司', '1');
INSERT INTO `branch` VALUES ('5', '西南区分公司', '1');
INSERT INTO `branch` VALUES ('6', '北京分公司', '1');
INSERT INTO `branch` VALUES ('7', '华北区总裁办', '2');
INSERT INTO `branch` VALUES ('8', '华北区人事部', '2');
INSERT INTO `branch` VALUES ('9', '华北区财务部', '2');
CREATE TABLE `member` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(255) NOT NULL DEFAULT '' COMMENT '成员名称',
  `sex` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '性别',
  `age` tinyint(3) unsigned NOT NULL DEFAULT '25' COMMENT '年龄',
  `type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '是否为领导',
  `branch_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '所属部门',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `member` VALUES ('1', '刘一二(CEO)', '0', '25', '0', '1');
INSERT INTO `member` VALUES ('2', '赵三四(COO)', '0', '25', '0', '1');
INSERT INTO `member` VALUES ('3', '华北区负责人', '0', '25', '0', '2');
INSERT INTO `member` VALUES ('4', '东北区负责人', '0', '25', '0', '3');

组合模式代码(为了链接数据库方便,这里直接使用的是thinkphp中的DB方法):

<?php

namespace app\design\fade\bombin;

//成员、部门的统一对象
use think\Db;
use think\Exception;

class Branch
{
    protected $id;      //当前对象ID
    protected $data;    //当前对象的数据
    protected $type;    //当前对象的类型(0-部门 1-成员)

    protected $branch_id;           //当前部门ID
    
    /**
     * 初始化对象
     * @author Renling
     * @datetime 10:18 2019/2/19
     *
     * @access public
     * @param $id int 对象ID
     **/
    public function __construct($id = null, $type = 0)
    {
        $this->type = $type;
        if ($type==0) {
            //如果ID为null的时候,获取最顶端的部门ID
            $this->id = $this->branch_id = $id?:$this->getHighestBranchId();
        } else {
            if (empty($id)) {
                throw new Exception('member id is not null');
            }
            $this->id = $id;
            $this->branch_id = $this->getBranchId();
        }
        $this->data = $this->getData();
    }
    /**
     * 获取最高级的部门ID
     * @author Renling
     * @datetime 10:22 2019/2/19
     *
     * @access protected
     *
     * @return integer
     **/
    protected function getHighestBranchId()
    {
        $data = Db::table('branch')->where([
            'parent_id' => 0
        ])->find();
        if (!empty($data)) {
            return $data['id'];
        }
        return null;
    }
    /**
     * 获取当前成员对象的所属部门ID
     * @author Renling
     * @datetime 11:43 2019/2/19
     *
     * @access protected
     *
     * @return string
     **/
    protected function getBranchId()
    {
        $id = $this->id;
        $data = Db::table('member')->find($id);
        return $data['branch_id'];
    }
    /**
     * 获取当前对象的数据
     * @author Renling
     * @datetime 11:48 2019/2/19
     *
     * @access protected
     *
     * @return array
     **/
    protected function getData()
    {
        $id = $this->id;
        if ($this->type==0) {
            $data = $this->getBranchData(compact('id'));
        } else {
            $data = $this->getMemberData(compact('id'));
        }
        if (isset($data[0])) {
            return $data[0];
        }
        return null;
    }
    /**
     * 获取当前部门的子级部门的ID值
     * @author Renling
     * @datetime 12:42 2019/2/19
     *
     * @access protected
     *
     * @return array
     **/
    protected function getChildrenBranchIds()
    {
        $parent_id = $this->branch_id;
        $branchIds = Db::table('branch')->field('id')->where(compact('parent_id'))->select();
        return array_column($branchIds, 'id');
    }
    /**
     * 获取成员的数据
     * @author Renling
     * @datetime 11:54 2019/2/19
     *
     * @access public
     * @param $where array 条件
     *
     * @return array
     **/
    public function getMemberData($where)
    {
        return Db::table('member')->where($where)->select();
    }
    /**
     * 获取部门的数据
     * @author Renling
     * @datetime 11:55 2019/2/19
     *
     * @access public
     * @param $where array 条件
     *
     * @return array
     **/
    public function getBranchData($where)
    {
        return Db::table('branch')->where($where)->select();
    }
    /**
     * 获取当前部门下的所有子级部门及部门成员
     * @author Renling
     * @datetime 12:38 2019/2/19
     *
     * @access public
     *
     * @return array
     **/
    public function getTree()
    {
        $branch_id = $id = $this->branch_id;
        $data = $this->getBranchData(compact('id'));
        $data = $data[0];
        $data['member'] = $this->getMemberData(compact('branch_id'));
        $children = $this->getChildrenBranchIds();
        foreach ($children as $branch_id) {
            $object = new Branch($branch_id);
            $data['children'][] = $object->getTree();
        }
        return $data;
    }
}

场景1,当某一个成员登陆时,可通过初始化函数进行加载,并通过getTree方法获取该成员所在的部门的子级部门树。

<?php
namespace app\design\controller;


use app\design\fade\bombin\Branch;
use think\Controller;

class Index extends Controller
{
    public function index()
    {
        $branch = new Branch(2, 1);
        halt($branch->getTree());
    }
}

场景2,当需要调用某一个部门的数据及其子级部门树的时候,也同样可以通过初始化函数进行实例化一个对象。

<?php
namespace app\design\controller;


use app\design\fade\bombin\Branch;
use think\Controller;

class Index extends Controller
{
    public function index()
    {
        $branch = new Branch(2);
        halt($branch->getTree());
    }
}

这里,把一组相似的对象(每一个部门为一个对象,每一个成员为一个对象)当作一个单一的对象,然后,把每个部门、成员通过树的形式组合在一起,这就是组合模式。

参考资料

《菜鸟教程——组合模式》http://www.runoob.com/design-pattern/composite-pattern.html

《大话设计模式》

下一篇

初始设计模式——迭代器模式

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值