现在的位置: 首页 > 综合 > 正文

设计模式 – 组合 Composite

2018年04月07日 ⁄ 综合 ⁄ 共 2125字 ⁄ 字号 评论关闭

1. 意图

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

Composite模式的关键是一个抽象类,它既可以代表图元,又开始代表图元的容器。

2.适用性

在以下情况使用Composite模式

你想表示对象的部分-整体层次结构

你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

3.类图

4. 参与着

Component, Leaf, Composite, Client

5. Composite的目的是为了为调用者提供操作的一致性,因此Leaf与Composite都继承自抽象的Component

要注意的是.NET Framework 中的 XMLNode ,TreeNode 提供的容器对象 并不继承自同样的接口,因此不是Composite模式

注意上图的add, remove和getChild()方法,通常这些被认为是声明管理子部件的操作,问题是对于Leaf对象,这些操作并没有意义

此时有两种办法:

1) 将add() remove()等操作定义在Composite中,不定义在Component中, 这种做法被称为  安全性

这种做法的缺点是Leaf  和 Composite有不同的接口,因此调用者必须知道调用的对象是Leaf还是Composite,做一个类型转换

2)  将add() remove() 等操作定义在 Component中,  这种做法被称为 透明性 

缺点是add , remove 对象可能会导致一些无意义的操作

通常会更加强调透明性(这正是Comosite模式的主要目的), 当然我们需要用一些技巧来避免透明性带来的缺点。

6. 实例

考虑以下的一个场景,某个大规模集团军的战斗

    class Program
    {
        static void Main(string[] args)
        {
          
        }
    }

    interface ICommand
    {
        void Attack();
        void Add(ICommand command);
        void Remove(ICommand command);
        string Name { get; set; }
        ICommand Owner { get; set; }
        List<ICommand> GetChilds();
        ICommand GetArmy();
    }

    class Army : ICommand
    {
        protected List<ICommand> cmdList = null;

        public Army(ICommand owner, string name)
        {
            this.Name = name;
            cmdList = new List<ICommand>();
        }

        public string Name { get; set; }
        public ICommand Owner { get; set; }

        public void Attack()
        {
            Console.WriteLine(Name + " joins the battle");
            foreach (ICommand cmd in cmdList)
                cmd.Attack();
        }

        public void Add(ICommand command)
        {
            command.Owner = this;
            cmdList.Add(command);
            Console.WriteLine(command.Name + " joins the " + Name);
        }

        public void Remove(ICommand command)
        {
            if (cmdList.IndexOf(command) > -1)
                cmdList.Remove(command);
            Console.WriteLine(command.Name + " leaves the " + Name);
        }

        public ICommand GetArmy()
        {
            return this;
        }

        public List<ICommand> GetChilds()
        {
            return cmdList;
        }
        
    }

    class Soldier : ICommand
    {
        public Soldier(ICommand owner, string name)
        {
            if (owner == null)
                throw new NotSupportedException("soldier must belong to an army");
            this.Name = name;
            this.Owner = owner;
        }

        public string Name
        {
            get;
            set;
        }

        public ICommand Owner
        {
            get;
            set;
        }

        public void Attack()
        {
            Console.WriteLine(Name + " joins the battle");
        }

        public void Add(ICommand command)
        { 
        }

        public void Remove(ICommand command)
        { 
        }

        public List<ICommand> GetChilds()
        {
            return null;
        }

        public ICommand GetArmy()
        {
            return null;
        }
    }

上面的代码没有调用者的部分,接下来讨论调用者

如果根据需要去创建不同的对象,然后add, remove ... 是一种方法,但是并不优雅

这个时候可以考虑Builder模式, Builder模式定义对象创建的步骤,使得不同的过程可以有不同的表示,非常适合Composite

抱歉!评论已关闭.