设计模式深入学习---Component组合模式(结构型模式)

          Component组合模式是一个非常好用而且经常可以在大型项目中看到的设计模式。
   首先我们来简单过一下什么是Component组合模式以及用该模式的情况和好处。Component组合模式就是将对象组合成树形结构以表示"部分-整体"的层次结构。

   Composite使得用户对单个对象和组合对象的使用具有一致性。比如我们在制作一个具有各种人物的游戏时,每个人物又各有各自特点鲜明的技能(魔兽争霸,英雄联盟,刀塔)。

  

a0.jpg (66.31 KB, 下载次数: 3)

下载附件  保存到相册

2016-9-4 18:33 上传


   那我们如果要制作一套这样的技能系统,怎么制定架构合适呢, 记得我们上一节说到Bridge桥接模式的用法,其实组合模式像桥接模式的 组合-整体的概念。Component组合模式的中心就是 组合-整体。制作成树状类型的管理,更方便我们的添加,修改,删除。下面先看下Component组合模式的使用例子。

abstract class Component
  {
      protected string name;
      public Component(string name)
      {
          this.name = name;
      }
 
      public abstract void Add(Component c);
      public abstract void Remove(Component c);
      public abstract void Display(int depth);
  }
 
  /// <summary>
  /// 叶子节点
  /// </summary>
  class Leaf : Component
  {
      public Leaf(string name)
          : base(name)
      {
 
      }
 
      public override void Add(Component c)
      {
          Console.WriteLine("叶子节点无法添加节点");
      }
 
      public override void Remove(Component c)
      {
          Console.WriteLine("叶子节点无法删除节点");
      }
 
      public override void Display(int  depth)
      {
          Console.WriteLine(new String('_', depth) + name);
      }
  }
 
 
  class Composite : Component
  {
      private List<Component> children = new List<Component>();
 
      public Composite(string name)
          : base(name)
      {
 
      }
 
      public override void Add(Component c)
      {
          children.Add(c);
      }
 
      public override void Remove(Component c)
      {
          children.Remove(c);
      }
 
      public override void Display(int depth)
      {
          Console.WriteLine(new String('_', depth) + name);
          foreach (Component c in children)
          {
              c.Display(depth + 2);
          }
      }
  }
     上述例子就是 添加了一个 Component组合的父类,该父类有添加删除和显示方法。 然后还有一个Leaf叶子节点的子类,和父类一样的方法。还有一个Composite 分支类,也继承于Component。但是这个分支类多一个list。里面存放全部我们需要添加的组合对象。好了,我们调用看看是什么情况。
Composite root = new Composite("树根");
       root.Add(new Leaf("树根叶子A"));
       root.Add(new Leaf("树根叶子B"));
 
       Composite comp = new Composite("分支A");
       comp.Add(new Leaf("分支A叶子A"));
       comp.Add(new Leaf("分支A叶子B"));
 
       root.Add(comp);
 
       Composite comp2 = new Composite("分支B");
       comp2.Add(new Leaf("分支B叶子A"));
       comp2.Add(new Leaf("分支B叶子B"));
 
       comp.Add(comp2);
 
       root.Add(new Leaf("树根叶子C"));
 
       Leaf leaf = new Leaf("树根叶子D");
 
       root.Add(leaf);
       root.Remove(leaf);
 
       root.Display(0);
 
       Console.Read();


  可以看到,这就是一个树状图,显示着我们添加的每一个子类。叶子节点没有Add和Remove方法,叶子节点无法继续延伸,而分支节点可以无限扩展。  这就是Component组合模式的核心思路。基于这样的思路,我们来尝试下实现一个简单的技能树系统。
abstract class Skills
{
    protected string name;
    public Skills(string name)
    {
        this.name = name;
    }
 
    public abstract void Add(Skills s); //增加
    public abstract void Remove(Skills s); //移除
    public abstract void Display(int depth); //显示
 
    public abstract void UseSkill(); //释放技能
}
 
/// <summary>
/// 具体的技能实现的树枝节点
/// </summary>
class ConcreteSkill : Skills
{
    private List<Skills> children = new List<Skills>();
 
    public ConcreteSkill(string name)
        : base(name)
    {
 
    }
 
    public override void Add(Skills s)
    {
        children.Add(s);
    }
 
    public override void Remove(Skills s)
    {
        children.Remove(s);
    }
 
    public override void Display(int depth)
    {
        Console.WriteLine(new String('_', depth) + name);
        foreach (Skills s in children)
        {
            s.Display(depth + 2);
        }
    }
 
    public override void UseSkill()
    {
        foreach (Skills s in children)
        {
            s.UseSkill();
        }
    }
}
 
/// <summary>
/// 暗夜精灵族技能
/// </summary>
class DarkElvesSkill : Skills
{
    public DarkElvesSkill(string name)
        : base(name)
    {
 
    }
 
    public override void Add(Skills s)
    {
      
    }
    public override void Remove(Skills s)
    {
        
    }
 
    public override void Display(int depth)
    {
        Console.WriteLine(new String('_', depth) + name);
    }
 
    public override void UseSkill()
    {
        Console.WriteLine(name + "暗夜精灵族技能");
    }
}
 
 
class HumanSkill : Skills
{
    public HumanSkill(string name)
        : base(name)
    {
 
    }
 
    public override void Add(Skills s)
    {
  
    }
    public override void Remove(Skills s)
    {
        
    }
 
    public override void Display(int depth)
    {
        Console.WriteLine(new String('_', depth) + name);
    }
 
    public override void UseSkill()
    {
        Console.WriteLine(name + "人族技能");
    }
}
  OK,技能树写好了,里面有一个虚方法 Skills 技能类。然后一个具体的技能子类。 然后在添加一个 暗夜精灵族技能类和一个人族技能子类。现在我们来实例化它们看看。
ConcreteSkill skillTree = new ConcreteSkill("技能树");
 
           ConcreteSkill DemonHunter = new ConcreteSkill("恶魔猎手");
           DemonHunter.Add(new DarkElvesSkill("恶魔猎手技能:献祭 "));
 
           skillTree.Add(DemonHunter);
 
           ConcreteSkill MountainKing = new ConcreteSkill("山丘之王");
           MountainKing.Add(new HumanSkill("山丘之王技能:震晕 "));
 
           skillTree.Add(MountainKing);
 
 
           ConcreteSkill rmbPlayer = new ConcreteSkill("人民币玩家");
           rmbPlayer.Add(new DarkElvesSkill("人民币玩家技能:献祭 "));
           rmbPlayer.Add(new HumanSkill("人民币玩家技能:震晕 "));
 
           skillTree.Add(rmbPlayer);
 
           Console.WriteLine("技能树模型:");
           skillTree.Display(1);
 
           Console.WriteLine("技能表:");
           skillTree.UseSkill();
           Console.ReadKey();
  我们声明了一个 恶魔猎手,拥有一个献祭技能的子节点。 一个山丘之王,拥有一个震晕技能的子节点。然后再来一个人民币玩家,人民币玩家拥有两个种族的技能。然后在声明一个Root树节点,就叫技能树,把他们3个都加入进来。 

   

      看到这里明白了Component组合模式的强大之处了么,只要都是在一个树形节点下,我们可以无限扩展延伸,技能下还可以继续加入其它子类。 而且都有添加,删除方法,自由移动组合。这样在我们后期要移动相关功能就变得非常简单。比如人族和暗夜族技能对调。甚至我们也可以用这样设计模式来设计人物种族类型,或者其他更复杂的设计。 
  好了,我们再来看看Component组合模式的几个要点: 
   Component组合模式采用树形结构来实现普遍存在的对象容器,从而将"一对多"的关系转化成"一对一"的关系,使得客户代码可以一致地处理对象和对象容器,
而无需关心处理的是单个对象,还是组合的对象容器。
   Component组合模式模式中,是将"Add"和"Remove"等和对象容器相关的方法定义在"表示抽象对象的Component类"中,还是将其定义在"表示对象容器的Composite类"中,是一个关乎"透明性"和"安全性"的两难问题,需要仔细权衡。这里有可能违背面向对象的"单一职责原则",但是对于这种特殊结构,
这又是必须付出的代价。
   Component组合模式在具体实现中,可以让父对象中搞得子对象反向追溯;如果父对象有频繁的遍历需求,可以用缓存技巧来改善效率.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值