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

一、引言

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

二、组合模式

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

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

  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("\n结构图");
            root.Display(0);
            Console.WriteLine("\n职责图");
            root.LineOfDuty();
            Console.Read();
        }

运行结果如下图

使用场景

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

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

优点

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

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

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

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

时间: 2024-08-07 13:19:36

面向对象编程思想-组合模式的相关文章

面向对象编程思想-命令模式

一.引言 起初餐馆吃饭都是客人和厨师直接沟通,菜谱是一样的,可是客人多了的时候,有的客人可能有急事不吃了要退单,还有的客人点很多菜需要记录类别和次序等现象,这时服务员角色的出现解决了问题.那么面对某些无法抵御变化的"紧耦合"的场景如何做程序设计呢?命令模式设计便出现了,使得"行为请求者"与"行为实现者"解耦,以便适应变化,让对象之间调用关系更加灵活.下面请看今天要学习的命令模式: 二.命令模式 定义:将一个请求封装为一个对象,从而使可用不同的请求

面向对象编程思想-解释器模式

一.引言 我们常常在会在字符串中搜索匹配字符或判断一个字符串是否符合我们要的格式时,使用正则表达式,可解决问题的背后是一种什么思想呢?即我们今天要学习的内容,解释器模式 二.解释器模式 定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子 1.文法:即语法规则.在解释器模式中每一个语法都对应一个解释器对象,用来处理相应的语法规则.它对于扩展.改变文法规则都很方便 2.可以通过抽象语法树(Abstract Syntax Tree,AST)的图形方式来

面向对象编程思想-建造者模式

一.引言 父母希望孩子们受到良好的教育,但孩子的培养是很复杂的,从认字,写字,颂词,到语数外理化生音体美的培养等等,如果让父母一个个这样培养孩子是很不容易的,这个时候就出现了学校,学校封装了孩子每一步的培养要做的事情,父母只需要把孩子送到学校,学校负责把培养好的孩子交换给父母.啊...这个例子就做抛砖引玉了,在程序设计中,同样存在这样的设计思想,下面介绍今天我们要学习的建造者模式 二.建造者模式 定义:将一个复杂对象的创建与它的表示分离,使得同样的构建过程创建出不同的表示.在这个例子中,家长和学

面向对象编程思想-策略模式

一.引言 平时去商场买东西,会遇到各种各样的商场促销活动,例如:黄金会员打9折,铂金会员打8折,钻石会员打7折...通常的做法,定义一个算法类,我们根据会员类型,使用if-else判断获得不同的算法.这样的确解决了问题,但是哪天商场新增活动了,要买300返100,我们就需要去修改算法类了,违背了"开放-封闭原则",我们认为这样的设计是不够友好的.这时我们可以考虑使用策略模式来解决这个问题 二.策略模式 定义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不

面向对象编程思想-代理模式

一.引言 在系统开发过程中,大多会遇到跨网络做系统应用间数据对接问题,但目标对象不允许跨网络直接访问数据,通常考虑到网络和安全性能等因素,开发者会在客户端和目标对象间添加一层中间层--代理层,也是即将要介绍的代理模式(Proxy). 二.代理模式介绍 在介绍代理模式前,我们首先看一下代理模式的分类 1.远程(Remote)代理:为一个位于不同地址空间的对象提供局部代表对象,隐藏一个对象存在于不同地址空间的事实. 典型例子:webservice在.NET中的应用,在应用程序项目中加入web引用,引

面向对象编程思想-原型模式

一.引言 相信大家都看过西游记中孙悟空拔一根汗毛吹出千万只猴子,可有没有想过如果这些猴子一只一只的去经历和孙悟空一样的成长过程才能产生,这是何其的复杂和耗费精力啊?!类比在程序设计中,当需要创建多个相同的类的实例,这个创建过程又是极其复杂时,使用new操作符一个个去创建会增加内存开销和程序复杂度.显然,采用工厂方法模式是不适合的,没必要每次都new一个相同的类的实例对象.建造者模式就更不用说了,是相同构建步骤创建不同的表示,一步步的创建也太麻烦了.那现在解决思路是 创建一个类的实例对象,如果后来

面向对象编程思想-模板方法模式

一.引言 说到模板,顾名思义:就是样板,整体架构已经有了,你只需要填充自己的特定内容就可以了.如:简历模板,论文模板,PPT模板等 在软件设计中,模板方法模式与之很相似,下面请看我们今天要学习的模板方法模式 二.模板方法模式 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 下面结构图: 抽象模板角色(AbstractClass):在抽象类中定义一个或多个基本操作,每一个操作对应算法中一个步骤:同时提供一个模板方法

面向对象编程思想-备忘录模式

一.引言 上篇博文中我们分享了访问者模式,访问者模式是把作用于数据结构上的操作封装到访问者类中,使得数据结构与操作分离.今天我们要学习的备忘录模式与命令模式有点相似,不同的是,命令模式保存的是发起人的具体命令(命令对应行为),而备忘录模式保存的是发起人的状态(状态对应数据内部结构,如属性).下面请看今天要学习的访问者模式 二.备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态 下面是备忘录模式的结构图: 下面是备

面向对象编程思想(OOP)

本文我将从面向对象编程思想是如何解决软件开发中各种疑难问题的角度,来讲述我们面向对象编程思想的理解,梳理面向对象四大基本特性.七大设计原则和23种设计模式之间的关系. 软件开发中疑难问题: 软件复杂庞大 很多软件进入维护阶段 需求的不断变更 软件开发中存在很多其他的问题,上面只是从程序开发和设计的角度看到的部分问题.需求解决上面软件开发中的问题,就要求我们编写(设计)的软件具有很好的可读性.可维护性和可扩展性.我们需要保证代码具有高内聚低耦合. 下面将简单介绍面向对象的一些基本特性.设计原则,以