设计模式(三)-结构型模式(4)-组合模式

一、为何需要组合模式(Composite)?

在代码设计中,有种情况是对象之间存在层次关系,即对象之间会存在父结点和子结点的关系。

比如在文件管理系统中,所有文件和文件夹形成树状结构,文件夹目录里存在子文件夹和文件。文件夹属于枝结点,文件属于叶结点。枝结点有下一个层级,所以可以对其子结点的对象进行移除或增加新对象的操作。而叶结点并没有移除和增加的操作,是因为它没有子结点。

对于这种对象之间存在的层级关系,我们可以使用组合模式来设计。

特点:

将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。(一致性:如文件夹和文件都有被打开的操作。所有文件夹对其子结点都有移除和增加新子结点的操作。)

结构:

组合对象的抽象接口(Component):定义组合对象的公共接口。(组合对象指的是所有结点。如文件系统的打开,移除和增加的功能接口)
叶结点具体类(Leaf):叶结点实现组合对象的抽象方法,但没有子结点。(如文件)
枝结点具体类(Composite):枝节点实现组合对象的抽象方法,并且有一个容器用来存储子结点。(如文件夹)

适合应用场景特点:

  • 对象之间存在层次结构,具有使用某些功能的一致性。

请添加图片描述

二、例子

需求:

一家公司里的部门有人事部、开发部、测试部、设计部。现在该公司又把测试部再分为软件测试组和硬件测试组。每个测试组都有一个组长。每当完成某个阶段任务时,公司要求每个部门以及测试部组长进行汇报工作进度的情况。

设计分析:

  • 枝结点:公司、人事部、开发部、设计部、测试部、软件测试组、硬件测试组。叶结点:软件测试组长和硬件测试组长。
  • 所有结点的公共动作:汇报工作。
  • 所有树枝结点都有增加和移除结点的操作。

1、定义组合对象的抽象接口:


    //Component:(组合对象的抽象接口,叶结点抽象接口)
    public abstract class Company
    {
        public string Name { get; protected set; }
        public abstract void reportWork();
    }

    //Component:(组合对象的抽象接口,枝结点抽象接口)
    public abstract class AbsComposite : Company
    {
        public abstract void Add(Company company);
        public abstract void Remove(Company company);
    }

2、定义叶结点具体类和枝结点具体类:


//Leaf:叶结点具体类(组长、同事成员)
    public class GroupLeader : Company
    {
        public GroupLeader(string name)
        {
            Name = name;
        }
        public override void reportWork()
        {
            Console.WriteLine(Name);
        }
    }

    //Composite:枝结点具体类(公司、部门)
    public class Composite : AbsComposite
    {
        private List<Company> _CompanyList = new List<Company>();//容器
        public List<Company> CompanyList { get { return _CompanyList; } }

        public Composite(string name)
        {
            this.Name = name;
        }

        public override void Add(Company company)
        {
            _CompanyList.Add(company);
        }

        public override void Remove(Company company)
        {
            _CompanyList.Remove(company);
        }

        public override void reportWork()
        {
            Console.WriteLine("The following members need to report their work to our company:");
            getCompanyList(CompanyList);
        }

        //不是组合对象的公共接口,是 Department 类私有的成员方法。
        //该方法是为了测试例子而用的,并不是学习组合模式的要点。可忽略。
        private void getCompanyList(List<Company> list)
        {
            foreach (var item in list)
            {

                var itemDepart = item as Composite;//枝结点
                if (itemDepart != null)
                {
                    if (itemDepart.CompanyList?.Count > 0)
                    {
                        Console.WriteLine();
                        Console.Write("【" + item.Name +"】" + "-");枝结点,有子结点
                        getCompanyList(itemDepart.CompanyList);
                        continue;
                    }

                    Console.WriteLine("【" + item.Name + "】");//枝结点,子结点为空
                }
                else
                    Console.Write("(" + item.Name + ")");//叶结点

            }

        }

    }

3、主程序:


    //主程序
    class Program
    {
        static void Main(string[] args)
        {
            AbsComposite root = new Composite("阳光组合公司");
            root.Add(new Composite("人事部"));
            root.Add(new Composite("开发部"));
            root.Add(new Composite("设计部"));
            
            var testDepartment = new Composite("测试部");
            var software = new Composite("软件测试组");
            var hardware = new Composite("硬件测试组");
            GroupLeader softwareLeader = new GroupLeader("软件测试组长");
            GroupLeader hardwareLeader = new GroupLeader("硬件测试组长");

            root.Add(testDepartment);
            testDepartment.Add(software);
            testDepartment.Add(hardware);
            software.Add(softwareLeader);
            hardware.Add(hardwareLeader);

            root.reportWork();//各部门和测试组长汇报工作

            Console.ReadLine();
        }
    }

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值