深入浅出学习设计模式(C#实现)-组合模式

本文深入探讨了在面对树形结构的组织需求时,如何利用设计模式进行有效解决。通过分析实例需求,作者指出简单复制和共享功能的方案不可行,并引入了组合模式的概念。组合模式允许部分与整体被一致对待,适用于有组织结构的场景。文章还附带了具体的C#代码实现,展示了如何构建树形结构的组合模式。
摘要由CSDN通过智能技术生成

看到组合模式,真的是有一种很开心的感觉。

一.看实例需求

为什么会这么说呢,请看下面的例子:如果有一个项目,为一家在全国许多城市都有分销机构的大公司做办公管理系统,总部包括人力资源/财务/运营等部门,名下的分公司或办事处就上述部门的功能也要有,并且总部,分部,办事处这些都是有组织结构的,不可以平行管理。如下图:


二.解方法利弊

首先,简单的复制是最糟糕的设计

其次,共享功能到各个分公司,即总部/分部/办事处共用一套代码

但是很悲催,上述的两个方法均被毙掉!其一就不用多说了,这样的实现实在是没有意义的,不能为了敲代码而敲代码!其二,也不能满足客户的要求:总部/分部/办事处呈树状结构,是有组织结构的,而不可以平行管理,所以也不可取。

三.组合模式

其实上述情况就是部分与整体的关系,上述情况,虽然有组织结构,但是功能是一样的,所以在这里实际就是整体与部分可以被一致对待的问题。

组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

如下结构图:


 四.树形结构-组合模式代码实现

具体实现代码如下(树形结构,根/分枝/叶结点)

namespace SJ_公司分公司_组合模式_树形结构实现_
{
    class Program
    {
        static void Main(string[] args)
        {
            //生成树根root,根上长出两片叶子,leafA和leafB
            Composite root = new Composite("root");
            root.Add(new Leaf("Leaf A"));
            root.Add(new Leaf("Leaf B"));

            //根上长出分枝Composite X,分枝上也有两叶LeafXA和LeafXB
            Composite comp = new Composite("Composite X");
            comp.Add(new Leaf ("Leaf XA"));
            comp.Add(new Leaf("Leaf XB"));

            root.Add(comp );

            //在Composite X上再长出分枝CompositeXY ,其分枝上也有两叶leafXYA和leafXYB
            Composite comp2 = new Composite("Composite XY");
            comp2.Add(new Leaf("Leaf XYA"));
            comp2.Add(new Leaf("Leaf XYB"));

            comp.Add(comp2);

            //根部又长出两叶leafC和leafD,可惜leafD没有长牢,被风吹走了
            root.Add(new Leaf("Leaf C "));

            Leaf leaf = new Leaf("Leaf D");
            root.Add(leaf);
            root.Remove(leaf);

            root.Display(1);//显示大树的样子

            Console.Read();

        }
        //组合模式:即将对象组合成树形结构以表示“部分-整体”的层次结构
        //虚拟类,Component为组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component的子部件
        abstract class Component
        {
            protected string name;

            public Component(string name)
            {
                this.name = name;
            }
            //通常用Add和Remove方法类提供增加或移除树叶或树枝的功能
            public abstract void Add(Component c);
            public abstract void Remove(Component c);
            public abstract void Display(int depth);
        }
        //叶结点(Leaf),叶结点没有子节点
        class Leaf : Component
        {
            public Leaf(string name)
                : base(name)
            { }

            public override void Add(Component c)
            {
                //由于叶结点没有再增加分枝和树叶,所以Add和Remove方法没有实现的意义,但这样做可以消除叶结点和枝节点对象在抽象层次的区别,
                //他们具备完全一致的接口
                Console.WriteLine("不能为叶结点再次增加分枝和树叶");
            }
            //同上
            public override void Remove(Component c)
            {
                Console.WriteLine("Can't remove from a leaf");
            }

            public override void Display(int depth)
            {
                //叶结点的具体方法,此处是显示其名称和级别
                Console.WriteLine(new string('-', depth) + name);
            }
        }
        //枝节点的行为(Composite)用来存储子部件,在Component接口中实现与子部件有关的操作,比如Add和Remove操作
        class Composite : Component
        {
            //一个字对象集合用来存储其下属的枝节点和叶结点
            private List<Component> children = new List<Component>();

            public Composite(string name)
                : base(name)
            { }

            public override void Add(Component c)
            {
                children.Add(c);
            }
            public override void Remove(Component c)
            {
                children.Remove(c);
            }
            public override void Display(int depth)
            {
                Console.WriteLine(new string ('-',depth )+name );
                //显示其枝节点名称,并对其下级进行遍历
                foreach (Component component in children)
                {
                    component.Display(depth +2);
                }
            }
        }
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值