• 面向对象编程思想-组合模式


    一、引言

    在软件开发中,我们经常会遇到处理简单对象和复合对象的情况,例如操作系统中文件目录的处理,目录可以包含单独的文件,也可以包括文件夹,而文件夹里又包含着文件,如此递归下去或者说是分级数据结构。由于简单对象和复合对象在功能上的区别,导致在操作过程中必须区分简单对象和复合对象,这样导致客户端调用时带来不必要的麻烦,作为客户,希望能够始终如一的对待简单对象和复杂对象。组合模式就是解决这个问题的

    二、组合模式

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

    来看看组合模式的基本代码结构

      abstract class Component
        {
            protected string name;
            public Component(string name)
            {
                this.name = name;
            }
            public abstract void Add(Component component);
            public abstract void Remove(Component component);
            public abstract void Display(int depth);
        }
      //Leaf在组合中表示叶节点对象
        class Leaf : Component
        {
            public Leaf(string name) : base(name) { }
            //由于叶子没有在增加分枝和树叶,所以ADD与Remove方法实现它没有意义;
            //但可以消除叶节点和枝节点在抽象层次的区别,它们具备完全一致的接口
            public override void Add(Component component)
            {
                Console.WriteLine("叶节点不允许添加树枝树叶节点");
            }
    
            public override void Display(int depth)
            {
                Console.WriteLine(new String('-',depth)+name);
            }
    
            public override void Remove(Component component)
            {
                Console.WriteLine("由于叶节点没有子节点,这里移除没有任何意义");
            }
        }
      class Composite : Component
        {
            private List<Component> Children = new List<Component>();
            public Composite(string name) : base(name) { }
            public override void Add(Component component)
            {
                Children.Add(component);
            }
            //显示枝节点名称并对其下级进行遍历
            public override void Display(int depth)
            {
                Console.WriteLine(new String('-',depth)+name);
                foreach (Component component in Children)
                {
                    component.Display(depth + 2);
                }
            }
    
            public override void Remove(Component component)
            {
                Children.Remove(component);
            }
        }
         static void Main(string[] args)
            {
                Composite root = new Composite("root");
                root.Add(new Leaf("Leaf A"));
                root.Add(new Leaf("Leaf B"));
                Composite comp = new Composite("Composite X");
                comp.Add(new Leaf("Leaf XA"));
                comp.Add(new Leaf("Leaf XB"));
                root.Add(comp);
                Composite comp2 = new Composite("Composite XY");
                comp2.Add(new Leaf("Leaf XYA"));
                comp2.Add(new Leaf("Leaf XYB"));
                comp.Add(comp2);
                root.Add(new Leaf("Leaf C"));
                Leaf leaf = new Leaf("Leaf D");
                root.Add(leaf);
                root.Remove(leaf);
                root.Display(0);
            Console.Read();
            }

    结果如下图所示:

    透明方式:在Component中声明所有管理子对象的方法,这样实现Component的子类都有Add和Remove方法,这样做的好处是叶节点和枝节点对于外界没有区别,它们具备完全一致的接口,但问题也很明显,Leaf本身没有Add和Remove方法,实现它是没有意义的

    安全方式:在Component中不去声明Add和Remove方法,那么子类Leaf就不需要实现它,而是在Composite中声明所有管理子类的方法,不过由于不够透明,树叶类和树枝类不具有相同的接口,客户端调用需要相应的判断,带来了不便

    下面是大话设计模式中公司管理系统的例子:

      public abstract class Company
        {
            protected string Name;
            public Company(string name)
            {
                this.Name = name;
            }
            public abstract void Add(Company company);
            public abstract void Remove(Company company);
            public abstract void Display(int depth);
            public abstract void LineOfDuty();
        }
       //具体公司类 树枝节点
        class ConcreteCompany : Company
        {
            //一个子对象集合 用来存储其下属的枝节点 叶节点
            private List<Company> Children = new List<Company>();
            public ConcreteCompany(string name) : base(name) { }
            public override void Add(Company company)
            {
                Children.Add(company);
            }
    
            public override void Display(int depth)
            {
                Console.WriteLine(new String('-',depth)+Name);
                foreach (Company com in Children)
                {
                    com.Display(depth+2);
                }
            }
    
            public override void LineOfDuty()
            {
                foreach (Company com in Children)
                {
                    com.LineOfDuty();
                }
            }
    
            public override void Remove(Company company)
            {
                Children.Remove(company);
            }
        }
       //人力资源部类 树叶节点
        class HRDepartment:Company
        {
            public HRDepartment(string name) :base(name)
            { }
    
            public override void Add(Company company)
            {
                
            }
    
            public override void Display(int depth)
            {
                Console.WriteLine(new String('-',depth)+Name);
            }
    
            public override void LineOfDuty()
            {
                Console.WriteLine($"{Name}员工招聘培训管理");
            }
    
            public override void Remove(Company company)
            {
                
            }
        }
      //财务部类  树叶节点
        class FinanceDepartment : Company
        {
            public FinanceDepartment(string name) : base(name) { }
            public override void Add(Company company)
            {
               
            }
    
            public override void Display(int depth)
            {
                Console.WriteLine(new String('-',depth)+Name);
            }
    
            public override void LineOfDuty()
            {
                Console.WriteLine($"{Name}公司财务收支管理");
            }
    
            public override void Remove(Company company)
            {
               
            }
        }
         static void Main(string[] args)
            {       
                ConcreteCompany root = new ConcreteCompany("北京总公司");
                root.Add(new HRDepartment("总公司人力资源部"));
                root.Add(new FinanceDepartment("总公司财务部"));
    
                ConcreteCompany comp = new ConcreteCompany("上海华东分公司");
                comp.Add(new HRDepartment("华东分公司人力资源部"));
                comp.Add(new FinanceDepartment("华东分公司财务部"));
                root.Add(comp);
                ConcreteCompany comp1 = new ConcreteCompany("南京分公司");
                comp1.Add(new HRDepartment("南京人力资源部"));
                comp1.Add(new FinanceDepartment("南京财务部"));
                comp.Add(comp1);
                ConcreteCompany comp2 = new ConcreteCompany("杭州分公司");
                comp2.Add(new HRDepartment("杭州人力资源部"));
                comp2.Add(new FinanceDepartment("杭州财务部"));
                comp.Add(comp2);
                Console.WriteLine("
    结构图");
                root.Display(0);
                Console.WriteLine("
    职责图");
                root.LineOfDuty();
                Console.Read();
            }

    运行结果如下图

    使用场景

    1.想表示对象部分-整体层次结构;

    2.希望用户忽略单个对象和组合对象的不同,统一的使用组合结构中的所有对象。

    优点

    1.高层模块不需要关心处理的是单个对象还是复合对象;客户程序可以像处理单个对象一样处理复合对象,将客户程序与复合对象容器结构解耦

    2.更容易往组合对象中添加新的构件,只需要找父节点即可

    缺点:设计更加复杂,使得客户需要更多时间理清类之间的层次关系

    关于组合模式的学习就到此结束了,希望能够帮到你,若有不足,欢迎斧正,感谢您的阅读。

  • 相关阅读:
    wpf ,tooltip的style
    WPF ,listbox,平滑滚动的2种方式。
    wpf ListBox,item两列不等高。
    wpf 背景镂空loading.....
    wpf treeView,避免横向滚动条自动偏移。 ContentHorizontalOffset
    wpf 时间控件加今天 按钮
    RFID相关知识总结(超高频UHF)
    WebSockets客户端示例
    WPF和WinForm的区别, 数据驱动与事件驱动的优势对比
    Unity容器实现自动注册
  • 原文地址:https://www.cnblogs.com/jdzhang/p/7081521.html
Copyright © 2020-2023  润新知