所谓组合模式,即将对象组合成树形结构以表示”部分-整体“的层次结构,其具体作用表现为使得单个对象和组合对象的使用具有一致性。

        举个栗子(烫手),我们想要设计出一种公司框架,这个公司框架里上有总公司分公司,下有财务部人事部等。通常的话我们会将每个部分给设计为单个类,如总公司一个类,里面有总公司的功能;分公司一个类,有分公司的功能;每个分公司下方还有不同的部门,它们也是单独的类。假设我们这么设计了,这时候如果有三个分公司,每个分公司有六个部门,那么这就要写十八个类,而且这些类还要与不同的分公司区分开来(因为上海分公司的人事部不可能招人招到广州的分公司里吧)。要是真的这么写出来的话,维护一大难事,万一新开了个分公司,那又会是一场灾难。

        这时候就可以考虑使用组合模式。它的主要作用就是对待单个对象的“态度”和组合对象的“态度”是一样的。这样我们就不用考虑谁是谁的部门,谁是分公司总公司了,而且使用方式是统一的,开发起来更加方便。

        Talk is cheap. Show me the code!!!!

public abstract class Company
    {
        protected string name;
        public Company(string name)
        {
            this.name = name;
        }

        public abstract void Add(Company c);
        public abstract void Remove(Company c);
        public abstract void Display(int depth);
        public abstract void LineOfDuty();
    }

    public class ConcreateCompany : Company
    {
        private List<Company> children = new List<Company>();
        public ConcreateCompany(string name):base(name)
        {

        }

        public override void Add(Company c)
        {
            children.Add(c);
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new string('-', depth) + name);
            foreach (var item in children)
            {
                item.Display(depth + 2);
            }
        }

        public override void LineOfDuty()
        {
            foreach (var item in children)
            {
                item.LineOfDuty();
            }
        }

        public override void Remove(Company c)
        {
            children.Remove(c);
        }
    }

    public class HRDepartment : Company
    {

        public HRDepartment(string name):base(name)
        {

        }

        public override void Add(Company c)
        {
            Console.WriteLine("Can not add to a HRDepartment");
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new string('-', depth) + name);
        }

        public override void LineOfDuty()
        {
            Console.WriteLine("{0}员工招聘培训管理", name);
        }

        public override void Remove(Company c)
        {
            Console.WriteLine("Can not remove to a HRDepartment");
        }
    }

    public class FinaceDepartment : Company
    {
        public FinaceDepartment(string name):base(name)
        {

        }
        public override void Add(Company c)
        {
            Console.WriteLine("Can not to add a FinaceDepartment");
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new string('-', depth) + name);
        }

        public override void LineOfDuty()
        {
            Console.WriteLine("{0}公司财务收支管理", name);
        }

        public override void Remove(Company c)
        {
            Console.WriteLine("Can not remove to a FinaceDepartment");
        }
    }

        我们来解读这一长串代码。首先我们将公司及部门抽象出来,找出它们共同点,即使有些功能是对方没有的,我们也抽取出来组成抽象类Company,即新增部门的抽象方法Add,砍掉某个部门的抽象方法Remove,部门所属的公司Display,部门需履行的职责LineOfDuty;接着我们定义了公司类ConcreateCompany来继承Company并实现其抽象方法,因为是可以设立总公司及分公司的嘛;最后我们定义人事部HRDepartment类及财务部FinaceDepartment类使其分别继承Company并实现其抽象方法。这时候可以发现,我们是把部门当作公司来使用,因为公司需要履行职责,部门同样需要,公司可以显示归属,部门同样可以。

        解读完毕,下面我们来看一下使用示例:

class Program
    {
        static void Main(string[] args)
        {
            ConcreateCompany cc = new ConcreateCompany("北京总公司");
            cc.Add(new HRDepartment("总公司人力资源部"));
            cc.Add(new FinaceDepartment("总公司财务部"));

            ConcreateCompany cc2 = new ConcreateCompany("广州分公司");
            cc2.Add(new HRDepartment("广州分公司人力资源部"));
            cc2.Add(new FinaceDepartment("广州分公司财务部"));

            ConcreateCompany cc3 = new ConcreateCompany("杭州分公司");
            cc3.Add(new HRDepartment("杭州分公司人力资源部"));
            cc3.Add(new FinaceDepartment("杭州分公司财务部"));

            cc.Add(cc2);
            cc.Add(cc3);

            Console.WriteLine("结构图:\n");
            cc.Display(1);

            Console.WriteLine("职责:\n");
            cc.LineOfDuty();

            Console.ReadKey();
        }
    }

        首先我们实例化了一个总公司,并向其增设了人事部及财务部;接着公司有钱了,又在广州及杭州增设分公司,同样有人事部及财务部;最后两处分公司同属于总公司管控,所以需要将这两个分公司添加到总公司中。然后我们就可以直接调用总公司的Display方法来展示公司的架构图,并且可以直接使所有公司的不同部门同时开始工作(调用LineOfDuty)。最后我们来看下运行结果:

        细心的朋友应该发现了我们设计出来的部门类也会有增加部门及砍掉部门的方法,这是不太合理的。那为什么还是这么写呢?这是因为我们将部门及公司提到了一个等级,对外界调用完全没有区别,因为它们具备完全一致的行为接口,但是这也是一大问题,因为这两个功能对于其子类来说是公开透明的,可是部门不需要有这两个功能,所以实现它们是没有意义的。如果我们将这两个功能提到公司类里的话,这保证了功能的安全性和隐秘性,但是我们在使用的时候就得去考虑当前对象是不是具备该功能,然后才能执行。这就是组合模式中的透明方式和安全方式两种不同的设计理念。

        好了,以上就是组合模式的讲解及示例,最后thanks for reading!!!!

注:本人的设计模式系列是根据大话设计模式一书中的内容,加以自身总结说明,一方面想多锻炼自身的表达能力,另一方面希望能够提升自身的编程能力及代码架构水平。若是能让更多的人通过我的文章来明白该设计模式的作用、应用场景及独立设计出来,当然也是对我个人表达能力的提升及掌握程度的认可。最后再次说明,本文内容来自大话设计模式一书,我只是写出来并加以总结希望达到熟练掌握的程度。如果你通过本文搞懂了,那么50%归功于此书,49%归功于你自己,1%为本人(脸都不要了)。

更多推荐