深入剖析设计模式中的组合模式应用及在C++中的实现

 更新时间:2016年03月11日 09:42:04   作者:梦在天涯  
这篇文章主要介绍了设计模式中的组合模式应用及在C++中的实现,组合模式可以清晰地反映出递归构建树状的组合结构,需要的朋友可以参考下

组合模式将对象组合成树形结构以表示“部分-整体”的层次结构。C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性。

模式图:

201631193912941.jpg (571×257)

适用场景:

  • 你想表示对象的部分-整体层次结构。
  • 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

举例:

namespace FactoryMethod_DesignPattern
{
  using System;
  using System.Collections;

  abstract class Component 
  {
    protected string strName;

    public Component(string name)
    {
      strName = name;
    }

    abstract public void Add(Component c);
  
    public abstract void DumpContents();
    
    // other operations for delete, get, etc.
  }

  class Composite : Component
  {
    private ArrayList ComponentList = new ArrayList();
    
    public Composite(string s) : base(s) {}

    override public void Add(Component c)
    {
      ComponentList.Add(c);
    }

    public override void DumpContents()
    {
      // First dump the name of this composite node
      Console.WriteLine("Node: {0}", strName);

      // Then loop through children, and get then to dump their contents
      foreach (Component c in ComponentList)
      {
        c.DumpContents();
      }
    }
  }

  class Leaf : Component
  {
    public Leaf(string s) : base(s) {}

    override public void Add(Component c)
    {
      Console.WriteLine("Cannot add to a leaf");
    }

    public override void DumpContents()
    {
      Console.WriteLine("Node: {0}", strName);
    }
  }

  /// <summary>
  ///  Summary description for Client.
  /// </summary>
  public class Client
  {
    Component SetupTree()
    {
      // here we have to create a tree structure, 
      // consisting of composites and leafs.   
      Composite root = new Composite("root-composite");
      Composite parentcomposite;
      Composite composite;
      Leaf leaf;

      parentcomposite = root;
      composite = new Composite("first level - first sibling - composite");
      parentcomposite.Add(composite);
      leaf = new Leaf("first level - second sibling - leaf");
      parentcomposite.Add(leaf);
      parentcomposite = composite; 
      composite = new Composite("second level - first sibling - composite");
      parentcomposite.Add(composite);
      composite = new Composite("second level - second sibling - composite");
      parentcomposite.Add(composite);

      // we will leaf the second level - first sibling empty, and start 
      // populating the second level - second sibling 
      parentcomposite = composite; 
      leaf = new Leaf("third level - first sibling - leaf");
      parentcomposite.Add(leaf);
      
      leaf = new Leaf("third level - second sibling - leaf");
      parentcomposite.Add(leaf);
      composite = new Composite("third level - third sibling - composite");
      parentcomposite.Add(composite);

      return root;
    }

    public static int Main(string[] args)
    {  
        Component component;
      Client c = new Client();
      component = c.SetupTree();

      component.DumpContents();
      return 0;
    }
  }
}


可以看出,Composite类型的对象可以包含其它Component类型的对象。换而言之,Composite类型对象可以含有其它的树枝(Composite)类型或树叶(Leaf)类型的对象。

合成模式的实现根据所实现接口的区别分为两种形式,分别称为安全模式和透明模式。合成模式可以不提供父对象的管理方法,但合成模式必须在合适的地方提供子对象的管理方法(诸如:add、remove、getChild等)。

透明方式

作为第一种选择,在Component里面声明所有的用来管理子类对象的方法,包括add()、remove(),以及getChild()方法。这样做的好处是所有的构件类都有相同的接口。在客户端看来,树叶类对象与合成类对象的区别起码在接口层次上消失了,客户端可以同等同的对待所有的对象。这就是透明形式的合成模式。

这个选择的缺点是不够安全,因为树叶类对象和合成类对象在本质上是有区别的。树叶类对象不可能有下一个层次的对象,因此add()、remove()以及getChild()方法没有意义,是在编译时期不会出错,而只会在运行时期才会出错。

安全方式

第二种选择是在Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的做法,因为树叶类型的对象根本就没有管理子类对象的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。

这个选择的缺点是不够透明,因为树叶类和合成类将具有不同的接口。

这两个形式各有优缺点,需要根据软件的具体情况做出取舍决定。

安全式的合成模式实现: 只有composite有Add ,remove,delete等方法.

以下示例性代码演示了安全式的合成模式代码:

// Composite pattern -- Structural example 
using System;
using System.Text;
using System.Collections;

// "Component"
abstract class Component
{
 // Fields
 protected string name;

 // Constructors
 public Component( string name )
 {
  this.name = name;
 }

 // Operation
 public abstract void Display( int depth );
}

// "Composite"
class Composite : Component
{
 // Fields
 private ArrayList children = new ArrayList();

 // Constructors
 public Composite( string name ) : base( name ) {}

 // Methods
 public void Add( Component component )
 {
  children.Add( component );
 }
 public void Remove( Component component )
 {
  children.Remove( component );
 }
 public override void Display( int depth )
 {
  Console.WriteLine( new String( '-', depth ) + name );

  // Display each of the node's children
  foreach( Component component in children )
   component.Display( depth + 2 );
 }
}

// "Leaf"
class Leaf : Component
{
 // Constructors
 public Leaf( string name ) : base( name ) {}

 // Methods
 public override void Display( int depth )
 {
  Console.WriteLine( new String( '-', depth ) + name );
 }
}

/// <summary>
/// Client test
/// </summary>
public class Client
{
 public static void Main( string[] args )
 {
  // Create a tree structure
  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 );

  root.Add( new Leaf( "Leaf C" ));

  // Add and remove a leaf
  Leaf l = new Leaf( "Leaf D" );
  root.Add( l );
  root.Remove( l );

  // Recursively display nodes
  root.Display( 1 );
 }
}

 透明式的合成模式实现: 每个里都有add,remove等修改方法.
以下示例性代码演示了安全式的合成模式代码:

// Composite pattern -- Structural example 

using System;
using System.Text;
using System.Collections;

// "Component"
abstract class Component
{
 // Fields
 protected string name;

 // Constructors
 public Component( string name )
 { this.name = name; }

 // Methods
 abstract public void Add(Component c);
 abstract public void Remove( Component c );
 abstract public void Display( int depth );
}

// "Composite"
class Composite : Component
{
 // Fields
 private ArrayList children = new ArrayList();

 // Constructors
 public Composite( string name ) : base( name ) {}

 // Methods
 public override void Add( Component component )
 { children.Add( component ); }
 
 public override void Remove( Component component )
 { children.Remove( component ); }
 
 public override void Display( int depth )
 { 
  Console.WriteLine( new String( '-', depth ) + name );

  // Display each of the node's children
  foreach( Component component in children )
   component.Display( depth + 2 );
 }
}

// "Leaf"
class Leaf : Component
{
 // Constructors
 public Leaf( string name ) : base( name ) {}

 // Methods
 public override void Add( Component c )
 { Console.WriteLine("Cannot add to a leaf"); }

 public override void Remove( Component c )
 { Console.WriteLine("Cannot remove from a leaf"); }

 public override void Display( int depth )
 { Console.WriteLine( new String( '-', depth ) + name ); }
}

/// <summary>
/// Client test
/// </summary>
public class Client
{
 public static void Main( string[] args )
 {
  // Create a tree structure
  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 );

  root.Add( new Leaf( "Leaf C" ));

  // Add and remove a leaf
  Leaf l = new Leaf( "Leaf D" );
  root.Add( l );
  root.Remove( l );

  // Recursively display nodes
  root.Display( 1 );
 }
}

实例

再看看一个完整些的例子:

#include <iostream> 
#include <string> 
#include <list> 
using namespace std; 
 
class Component 
{ 
protected: 
  string name; 
public: 
  Component(string name) 
    :name(name) 
  {  } 
  virtual void AddComponent(Component *component) {  } 
  virtual void RemoveComponent(Component *component) {  } 
  virtual void GetChild(int depth)  { } 
}; 
 
class Leaf: public Component 
{ 
public: 
  Leaf(string name) 
    :Component(name) 
  {  } 
  void AddComponent(Component *component) 
  { 
    cout<<"Leaf can't add component"<<endl; 
  } 
  void RemoveComponent(Component *component) 
  { 
    cout<<"Leaf can't remove component"<<endl; 
  } 
  void GetChild(int depth) 
  { 
    string _tmpstring(depth, '-'); 
    cout<<_tmpstring<<name<<endl; 
  } 
}; 
 
class Composite:public Component 
{ 
private: 
  list<Component*> _componets; 
 
public: 
  Composite(string name) 
    :Component(name) 
  { } 
  void AddComponent(Component *component) 
  { 
    _componets.push_back(component); 
  } 
  void RemoveComponent(Component *component) 
  { 
    _componets.remove(component); 
  } 
  void GetChild(int depth) 
  { 
    string tmpstring (depth, '-'); 
    cout<<tmpstring<<name<<endl; 
    list<Component*>::iterator iter = _componets.begin(); 
    for(; iter != _componets.end(); iter++) 
    { 
      (*iter)->GetChild(depth + 2); 
    } 
  } 
}; 
 
int main() 
{ 
  Composite *root = new Composite("root"); 
  Leaf *leaf1 = new Leaf("leaf1"); 
  Leaf *leaf2 = new Leaf("leaf2"); 
  root->AddComponent(leaf1); 
  root->AddComponent(leaf2); 
 
  Composite *lay2 = new Composite("layer2"); 
  Leaf *leaf4 = new Leaf("leaf4"); 
  lay2->AddComponent(leaf4); 
 
  Composite *lay1 = new Composite("layer1"); 
  Leaf *leaf3 = new Leaf("leaf3"); 
  lay1->AddComponent(leaf3); 
  lay1->AddComponent(lay2); 
 
  root->AddComponent(lay1); 
 
  root->GetChild(1); 
  cout<<endl; 
  lay1->GetChild(1); 
  cout<<endl; 
  lay2->GetChild(1); 
 
  delete root; 
  delete lay1; 
  delete lay2; 
  delete leaf1; 
  delete leaf2; 
  delete leaf3; 
  delete leaf4; 
  system("pause"); 
  return 0; 
} 

输出:

201631193949446.png (681×439)

相关文章

  • C语言 详细讲解逻辑运算符的使用

    C语言 详细讲解逻辑运算符的使用

    在C语言中,逻辑运算符有&&、||、!;&&表示“与”的意思,需要两端的表达式的值都为true,该式的值才为true。||表示“或”的意思,两端的表达式的值只要有一端为true,该式的值就为true。!表示“非”的意思,将该式的真值换成相反的真值,即false和true互换
    2022-04-04
  • C++中的常对象与常对象成员详解

    C++中的常对象与常对象成员详解

    常成员函数可以访问常对象中的数据成员,但仍然不允许修改常对象中数据成员的值。有时在编程时有要求,一定要修改常对象成员中的某个数据成员的值(例如类中有一个用于计数的变量count,其值应当不能变化)
    2013-10-10
  •  C++ new 和 delete 关键字详解

     C++ new 和 delete 关键字详解

    这篇文章主要介绍了 C++ new 和 delete 关键字详解,文章围绕主题展开new 和 delete 的使用方法的介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • C语言利用链表实现学生成绩管理系统

    C语言利用链表实现学生成绩管理系统

    这篇文章主要为大家详细介绍了C语言如何利用链表实现学生成绩管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-11-11
  • new和malloc的区别深入解析

    new和malloc的区别深入解析

    以下是分别是对new和malloc的区别进行了详细的分析及介绍,需要的朋友可以过来参考下
    2013-09-09
  • 浅谈Qt中使用CEF的几个要点(Windows下)

    浅谈Qt中使用CEF的几个要点(Windows下)

    下面小编就为大家带来一篇浅谈Qt中使用CEF的几个要点(Windows下)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • ​​​​​​​C语言实现单链表基本操作方法

    ​​​​​​​C语言实现单链表基本操作方法

    这篇文章主要介绍了​​​​​​​C语言实现单链表基本操作方法,文章围绕主题展开详细介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • socket编程之bind()函数使用示例详解

    socket编程之bind()函数使用示例详解

    这篇文章主要为大家介绍了socket编程之bind()函数使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • C++验证LeetCode包围区域的DFS方法

    C++验证LeetCode包围区域的DFS方法

    这篇文章主要介绍了C++验证LeetCode包围区域的DFS方法,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++程序自动重启的实现代码

    C++程序自动重启的实现代码

    自动重启原理很简单,用一个进程监控另一个进程,挂了就再启动一个,细节也不算多,主要是正确判断进程状态和启动方式,本文就给大家讲讲C++程序自动重启的实现方法,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-04-04

最新评论