无废话C#设计模式之十一:Composite

2016-02-19 13:46 3 1 收藏

下面请跟着图老师小编一起来了解下无废话C#设计模式之十一:Composite,精心挑选的内容希望大家喜欢,不要忘记点个赞哦!

【 tulaoshi.com - 编程语言 】

  本系列文章将向大家介绍一下C#的设计模式,此为第十一篇文章,相信对大家会有所帮助的。废话不多说,继续来看。

  意图

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

  场景

  我们知道,一个网络游戏通常会有多个游戏大区。每一个游戏大区会有很多游戏服务器(一个游戏大区就是一组游戏服务器)。每一个游戏服务器上会有不同的服务(可以是多个服务)。这是一个明显的部分-整体关系,假设我们现在需要制作一个服务器管理工具,用于显示所有大区、服务器以及服务的信息,并且能开启这些服务(可以是单独开启一个服务,也可以是开启整个服务器上的所有服务,也可以是开启整个大区的所有服务)。

  可以看到,游戏服务器和游戏大区都是一个组合对象,而游戏服务是最底层的节点。客户端在开启一个游戏大区服务的时候,必须和游戏服务器以及游戏服务进行依赖,而在开启游戏服务器上所有服务的时候,必须和游戏服务进行依赖。试想一下,如果一个公司的总裁在管理上不但需要和各总监以及经理进行沟通,还有和底层的员工沟通,那么总裁是不是会太忙碌了一点?由此,我们引入组合模式,使组合对象和单个对象具有一样的表现形式。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  示例代码

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace CompositeExample
  {
  class Program
  {
  static void Main(string[] args)
  {
  Element server1 = new GameServer("GS1", "192.168.0.1");
  server1.Add(new GameService("Lobby1", 1, "S5Lobby1"));
  server1.Add(new GameService("Gate1", 2, "S5Gate1"));
  server1.Add(new GameService("DataExchange1", 3, "S5DataExchange1"));
  server1.Add(new GameService("Rank1", 4, "S5Rank1"));
  server1.Add(new GameService("Log1", 5, "S5Log1"));
  Element server2 = new GameServer("GS2", "192.168.0.2");
  server2.Add(new GameService("Lobby2", 1, "S5Lobby2"));
  server2.Add(new GameService("Gate2", 2, "S5Gate2"));
  server2.Add(new GameService("DataExchange2", 3, "S5DataExchange1"));
  server2.Add(new GameService("Rank2", 4, "S5Rank2"));
  server2.Add(new GameService("Log2", 5, "S5Log2"));
  Element area = new GameArea("电信区");
  area.Add(server1);
  area.Add(server2);
  area.Display();
  area.Start();
  area.Stop();
  }
  }
  abstract class Element
  {
  protected string name;
  public Element(string name)
  {
  this.name = name;
  }
  public abstract void Add(Element element);
  public abstract void Remove(Element element);
  public abstract void Display();
  public abstract void Start();
  public abstract void Stop();
  }
  class GameService : Element, IComparable
  {
  private int serviceType;
  private string serviceName;
  public GameService(string name, int serviceType, string serviceName)
  : base (name)
  {
  this.serviceName = serviceName;
  this.serviceType = serviceType;
  }
  public override void Add(Element element)
  {
  throw new ApplicationException("xxx");
  }
  public override void Remove(Element element)
  {
  throw new ApplicationException("xxx");
  }
  public override void Display()
  {
  Console.WriteLine(string.Format("name:{0},serviceType:{1},serviceName:{2}", name, serviceType, serviceName));
  }
  public override void Start()
  {
  Console.WriteLine(string.Format("{0} started", name));
  }
  public override void Stop()
  {
  Console.WriteLine(string.Format("{0} stopped", name));
  }
  public int CompareTo(GameService other)
  {
  return other.serviceType.CompareTo(serviceType);
  }
  }
  class GameServer : Element
  {
  private string serverIP;
  private List serviceList = new List();
  public GameServer(string name, string serverIP)
  : base(name)
  {
  this.serverIP = serverIP;
  }

以下是引用片段:
  public override void Add(Element element)
  {
  serviceList.Add((GameService)element);
  }
  public override void Remove(Element element)
  {
  serviceList.Remove((GameService)element);
  }
  public override void Display()
  {
  Console.WriteLine(string.Format("{0}{1}({2}){3}", new string('+', 10), name, serverIP, new string('+', 10)));
  foreach (Element element in serviceList)
  {
  element.Display();
  }
  }
  public override void Start()
  {
  serviceList.Sort();
  Console.WriteLine("=============Starting the whole " + name + "=============");
  for (int i = 0; i  serviceList.Count; i++ )
  {
  serviceList[i].Start();
  }
  Console.WriteLine("=============The whole " + name + " started=============");
  }
  public override void Stop()
  {
  Console.WriteLine("=============Stopping the whole " + name + "=============");
  for (int i = serviceList.Count -1; i = 0; i--)
  {
  serviceList[i].Stop();
  }
  Console.WriteLine("=============The whole " + name + " stopped=============");
  }
  }
  class GameArea : Element
  {
  private List serverList = new List();
  public GameArea(string name)
  : base(name) { }
  public override void Add(Element element)
  {
  serverList.Add((GameServer)element);
  }
  public override void Remove(Element element)
  {
  serverList.Remove((GameServer)element);
  }
  public override void Display()
  {
  Console.WriteLine(new string('=',20));
  Console.WriteLine(" " + name);
  Console.WriteLine(new string('=', 20));
  foreach (Element element in serverList)
  {
  element.Display();
  }
  }
  public override void Start()
  {
  Console.WriteLine("=============Starting the whole " + name + "=============");
  foreach (Element element in serverList)
  {
  element.Start();
  }
  Console.WriteLine("=============The whole " + name + " started=============");
  }
  public override void Stop()
  {
  Console.WriteLine("=============Stopping the whole " + name + "=============");
  foreach (Element element in serverList)
  {
  element.Stop();
  }
  Console.WriteLine("=============The whole " + name + " stopped=============");
  }
  }
  }

  代码执行结果如下图:

  

  本系列文章将向大家介绍一下C#的设计模式,此为第十一篇文章,相信对大家会有所帮助的。废话不多说,继续来看。

  意图

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

  场景

  我们知道,一个网络游戏通常会有多个游戏大区。每一个游戏大区会有很多游戏服务器(一个游戏大区就是一组游戏服务器)。每一个游戏服务器上会有不同的服务(可以是多个服务)。这是一个明显的部分-整体关系,假设我们现在需要制作一个服务器管理工具,用于显示所有大区、服务器以及服务的信息,并且能开启这些服务(可以是单独开启一个服务,也可以是开启整个服务器上的所有服务,也可以是开启整个大区的所有服务)。

  可以看到,游戏服务器和游戏大区都是一个组合对象,而游戏服务是最底层的节点。客户端在开启一个游戏大区服务的时候,必须和游戏服务器以及游戏服务进行依赖,而在开启游戏服务器上所有服务的时候,必须和游戏服务进行依赖。试想一下,如果一个公司的总裁在管理上不但需要和各总监以及经理进行沟通,还有和底层的员工沟通,那么总裁是不是会太忙碌了一点?由此,我们引入组合模式,使组合对象和单个对象具有一样的表现形式。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  示例代码

以下是引用片段:
  using System;
  using System.Collections.Generic;
  using System.Text;
  namespace CompositeExample
  {
  class Program
  {
  static void Main(string[] args)
  {
  Element server1 = new GameServer("GS1", "192.168.0.1");
  server1.Add(new GameService("Lobby1", 1, "S5Lobby1"));
  server1.Add(new GameService("Gate1", 2, "S5Gate1"));
  server1.Add(new GameService("DataExchange1", 3, "S5DataExchange1"));
  server1.Add(new GameService("Rank1", 4, "S5Rank1"));
  server1.Add(new GameService("Log1", 5, "S5Log1"));
  Element server2 = new GameServer("GS2", "192.168.0.2");
  server2.Add(new GameService("Lobby2", 1, "S5Lobby2"));
  server2.Add(new GameService("Gate2", 2, "S5Gate2"));
  server2.Add(new GameService("DataExchange2", 3, "S5DataExchange1"));
  server2.Add(new GameService("Rank2", 4, "S5Rank2"));
  server2.Add(new GameService("Log2", 5, "S5Log2"));
  Element area = new GameArea("电信区");
  area.Add(server1);
  area.Add(server2);
  area.Display();
  area.Start();
  area.Stop();
  }
  }
  abstract class Element
  {
  protected string name;
  public Element(string name)
  {
  this.name = name;
  }
  public abstract void Add(Element element);
  public abstract void Remove(Element element);
  public abstract void Display();
  public abstract void Start();
  public abstract void Stop();
  }
  class GameService : Element, IComparable
  {
  private int serviceType;
  private string serviceName;
  public GameService(string name, int serviceType, string serviceName)
  : base (name)
  {
  this.serviceName = serviceName;
  this.serviceType = serviceType;
  }
  public override void Add(Element element)
  {
  throw new ApplicationException("xxx");
  }
  public override void Remove(Element element)
  {
  throw new ApplicationException("xxx");
  }
  public override void Display()
  {
  Console.WriteLine(string.Format("name:{0},serviceType:{1},serviceName:{2}", name, serviceType, serviceName));
  }
  public override void Start()
  {
  Console.WriteLine(string.Format("{0} started", name));
  }
  public override void Stop()
  {
  Console.WriteLine(string.Format("{0} stopped", name));
  }
  public int CompareTo(GameService other)
  {
  return other.serviceType.CompareTo(serviceType);
  }
  }
  class GameServer : Element
  {
  private string serverIP;
  private List serviceList = new List();
  public GameServer(string name, string serverIP)
  : base(name)
  {
  this.serverIP = serverIP;
  }

  代码说明

  Element类型就是抽象构件的角色,它给组合对象以及单个对象提供了一个一致的接口,使得它们都能有一致的行为。

  这里就出现一个问题,组合对象需要通过Add和Remove方法来为其添加子节点,而最底层的树叶构件下并没有任何子节点,在接口中定义这些操作子节点方法的方式叫做透明方式的合成模式,缺点就是不够安全,容易在运行时出现异常。如果把这些操作子节点的方法定义从抽象构件中删除,由各树枝构件来实现的话,就是安全方式的合成模式,缺点也就是不够透明。具体怎么做还要根据自己的需求。

  GameService当然就是树叶构件,如果调用它的Add以及Remove方法会抛出一个异常。当然,你也可以以其它方式来记录这种逻辑错误。

  GameServer是一个树枝构件。一个游戏服务器上会有多个游戏服务。这里注意到一点,在开启服务器上所有服务的时候,我们对服务进行了排序,排序是按照服务的类型进行的。然后,我们按照服务类型从大到小的次序开启了服务。一般一个网络游戏的服务会有很多种,而这些服务的开启是有先后次序的,先开记录日志的服务、排名服务、再开数据交换的服务、最后才是大厅服务等。我们不可能让用户进入大厅的时候没有地方写数据和日志吧。开启服务是按照次序的,那么关闭服务也就是按照相反的次序了。

  从上面这点,我们就可以看到组合模式的好处了,树枝构件在管理树叶构件的时候通常还会有一些逻辑,不会是简单的增加和删除操作。如果这些工作交给客户端去做的话,就太不合理了。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  最上层的树枝构件就是GameArea类型。它并没有什么特殊的地方。

  何时采用

  从代码角度来说,如果类型之间组成了层次结构,你希望使用统一的接口来管理每一个层次的类型的时候。

  从应用角度来说,如果你希望把一对多的关系转化为一对一的关系的时候。

  实现要点

  使用透明模式还是安全模式根据自己的需要定。

  在某些情况下,树叶构件可以访问树枝构件获取一些信息。

  如果树叶构件数量比较多,树枝构件频繁遍历子节点的话可以考虑进行缓存。

  既然所有对象有了统一的接口,客户端应该针对抽象构件进行编程。

上一篇:无废话C#设计模式之十:Flyweight
下一篇:无废话C#设计模式之十二:Bridge

来源:https://www.tulaoshi.com/n/20160219/1605185.html

延伸阅读
一、功能 保证一个类仅有一个实例。 三、优缺点 Singleton模式是做为"全局变量"的替代品出现的。所以它具有全局变量的特点:全局可见、贯穿应用程序的整个生命期,它也具有全局变量不具备的性质:同类型的对象实例只可能有一个。 四、实现 教科书上的Singleton定义如下: class Singleton { public: static Si...
OK,我又回来了,前面写了那么多,跟JAVA的对比也够多了,现在我就用我自己试验的例子,来看一看C#这个被称为JAVA#的新一代编程语言到底与JAVA有多大的区别. 首先我们建立一个C#的程序文件cs1.cs,然后再建立一个JAVA的源程序文件cs1.java.它们的内容分别是: cs1.cs: using System; public class cs1{ public static void Main(){ Console.Wri...
C#代码的外观和操作方式与C++和Java非常类似。初看起来,其语法可能比较混乱,不像书面英语和其他语言。但是,在C#编程中,使用的样式是比较清晰的,不用花太多的力气就可以编写出可读性很强的代码。 与其他语言的编译器不同,无论代码中是否有空格、回车符或tab字符(这些字符统称为空白字符),C#编译器都不考虑这些字符。这样格式化...
本文目的:根据近期开发的C#软件,对于软件的启动设计谈谈我的心得。 如下代码是我设计的启动软件的类,应用程序入口也是在这个普通类里面。 using System; using System.Threading; using System.Windows.Forms; namespace MainClass { public class MainApp { private static Mutex myMutex; private static bool requestInitialOwnersh...
C#中程序结构的关键概念为程序、命名空间、类型、成员和程序集。C#程序包括一个或多个源文件。程序中声明类型,类型包含成员并能够被组织到命名空间中。类和接口是类型的例子。字段、方法、属性和事件则是成员的例子。当C#程序被编译时,它们被物理地打包到程序集中。程序集的文件扩展名一般为.exe或者.dll,这取决于它们是实现为应用程序...

经验教程

872

收藏

22
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部