• Composite组合模式(结构型模式)


    1、概述

    在面向对象系统中,经常会遇到一些具有"容器性质"的对象,它们自己在充当容器的同时,也充当其他对象的容器.

    2、案例

    需要构建一个容器系统,需要满足以下几点要求:

    (1)、容器需要能创建和删除子容器

    (2)、但是整个系统有最终的容器结构一一取名SingleBox

    (3)、容器有自有业务逻辑,能执行指定的操作.

    实现如下:

            /// <summary>
            /// 容器接口
            /// </summary>
            public interface IBox
            {
                void Process();
    
                void AddBox(IBox box);
    
                void RemoveBox(IBox box);
            }
    
            /// <summary>
            /// 最终节点的容器,这个容器无法进行添加和删除子容器的操作
            /// </summary>
            public class SingleBox : IBox
            {
                public void Process()
                {
    
                }
    
                public void AddBox(IBox box)
                {
                    throw new Exception("SingleBox容器无法添加子容器");
                }
    
                public void RemoveBox(IBox box)
                {
                    throw new Exception("SingleBox容器无法移除子容器");
                }
            }
    
            /// <summary>
            /// 普通容器,可以进行添加和删除子容器的操作
            /// </summary>
            public class ContainerBox : IBox
            {
                private List<IBox> _containerBox = new List<IBox>();
    
                public void Process() { }
    
                /// <summary>
                /// 模拟实现,没有实际意义,表达一种概念,获取当前容器的子容器
                /// </summary>
                /// <returns></returns>
                public List<ContainerBox> GetBox()
                {
                    return _containerBox;
                }
    
                public void AddBox(IBox box)
                {
                    _containerBox.Add(box);
                }
    
                public void RemoveBox(IBox box)
                {
                    if (_containerBox.Contains(box))
                        _containerBox.Remove(box);
                }
            }

    调用代码如下:

            /// <summary>
            /// 第三方调用系统
            /// </summary>
            public class ThirdSystem
            {
                public void Run()
                {
                    IBox box = Factory.GetBox();
                    if (box is ContainerBox)
                    {
                        //如果当前容器是ContainerBox,执行该容器的Process方法
                        box.Process();
                        //获取该容器所有的子容器
                        var list = ((ContainerBox)box).GetBox();
                        //这里对所有的子容器进行递归操作,确保它们全部执行到类型为SingleBox
                    }
                    else if (box is SingleBox)
                    {
                        box.Process();
                    }
                }
            }

    分析客户端调用代码发现,客户端调用代码在获取容器的子容器时,需要递归处理子容器,从而使客户端代码与复杂的容器结构发生了耦合,这样在设计上是不合理,客户端代码不能承担这种复杂度,而是应该交给容器系统去处理这种复杂度.

    so,这种设计需要进行重构.

            /// <summary>
            /// 容器接口
            /// </summary>
            public interface IBox
            {
                void Process();
    
                void AddBox(IBox box);
    
                void RemoveBox(IBox box);
            }
    
            /// <summary>
            /// 最终节点的容器,这个容器无法进行添加和删除子容器的操作
            /// </summary>
            public class SingleBox : IBox
            {
                public void Process()
                {
    
                }
    
                public void AddBox(IBox box)
                {
                    throw new Exception("SingleBox容器无法添加子容器");
                }
    
                public void RemoveBox(IBox box)
                {
                    throw new Exception("SingleBox容器无法移除子容器");
                }
            }
    
            /// <summary>
            /// 普通容器,可以进行添加和删除子容器的操作
            /// </summary>
            public class ContainerBox : IBox
            {
                private List<IBox> _containerBox = new List<IBox>();
    
                //做一些容器该做的事情,比如说容器加载,做完之后卸载等等操作
    
                public void Process()
                {
                    if (_containerBox.Count > 0)
                    {
                        //遍历当前容器的所有子容器,然后执行子容器的操作,接着遍历该子容器的所有子容器
                        //进行它该进行的操作,循环这个操作,知道执行到SingleBox,因为它没有子容器,所有跳出
                        //Foreach循环,完成整颗容器树的遍历
                        foreach(IBox box in _containerBox)
                        {
                            box.Process();
                        }
                    }
                }
    
                public void AddBox(IBox box)
                {
                    _containerBox.Add(box);
                }
    
                public void RemoveBox(IBox box)
                {
                    if (_containerBox.Contains(box))
                        _containerBox.Remove(box);
                }
            }

    客户端调用代码如下:

            /// <summary>
            /// 第三方调用系统
            /// </summary>
            public class ThirdSystem
            {
                public void Run()
                {
                    IBox box = Factory.GetBox();
                    if (box is ContainerBox)
                    {
                        //Procss会遍历当前容器的所有的子容器,并且执行这些容器的方法
                        box.Process();
                      
                    }
                    else if (box is SingleBox)
                    {
                        box.Process();
                    }
                }
            }

    ok,现在的客户端调用代码与复杂的容器完成了解耦.而且完成了提出的需求.实现了对容器管理的同时,形成了一个树形结构.

    but,上面的代码还是存在缺陷,IBox接口承担了两种职责,一种是是维护容器,另一种是处理容器的结构,执行容器的方法,虽然违背了OOP职责单一的原则,但是这种代价可以接受.

    3、组合模式的要点

    (1)、重构的代码使用了组合模式,组合模式采用树形结构来实现普遍存在的对象容器,将原先暴露给客户端的"一对多"的关系转换为"一对一"的关系,使得客户端代码可以一致地处理容器对象,不需要关心处理的是单个对象还是含有树形结构的容器对象,将递归处理容器的复杂度交给组合模式来承担.

    (2)、将客户端调用代码与负责的容器结构解耦是Composite组合模式的核心思想,解耦之后,客户端代码与依赖的是容器抽象,而不是容器的内部实现结构,从而更能应对变化,试想以下,如果不这么做,如果容器对象发生改变,那么客户端就需要承受这种改变.

    (3)、Composite模式在具体的实现中.可以让父对象的子对象进行反向追溯,如果父对象有频繁的遍历需求,可以使用缓存来改善效率.

    (4)、Asp.Net中的控件大量使用了组合模式,可以参考帮助理解.

  • 相关阅读:
    宅急送
    网站迁移主要工作完成
    服务器迁移后性能提升很明显
    Vista修改默认字体
    服务器迁移预告
    Silverlight 2 和 Deep Zoom
    Mix 08到来之前的Monolight Update
    ASP.NET MVC Preview生命周期分析
    Windows Server 2008 与 .NET Framework 的版本之间有什么关系
    Silverlight 2 DispatcherTimer和通过XAML创建UI元素
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/9819038.html
Copyright © 2020-2023  润新知