C#设计模式之9——组合模式
2012-02-24 17:14
375 查看
一般情况下,组件可以是单独的一个对象,也可以是对象的组合,组合模式就是为了迎合这两种情况进行设计。组合可以被用来构建部分-整体层次结构,或者是构造树形的数据表示方式。组合是对象的集合,而其中的任何一个对象又可能是一个组合,或者是一个简单的对象。
在树形结构中,访问组合中所有的对象要求有一个简单的单一访问接口,但同时要求能够区分开节点和叶子。在构造组合的时候,我们需要决定哪个节点是元素哪个是叶子。在这里我们可以通过子节点个数进行判断是不是叶子节点。
比如构造一个公司的人事管理系统,经理下面有部门经理,部门经理下面有小组负责人,小组负责人下面有员工这样一个树形结构。在程序里我们需要显示每个人的成本,对于普通员工,一个人的成本就是他的工资,而对于部门经理,他的成本就是他的工资加上手下所有人的工资。
我们需要定义两种类:雇员类和老板类,雇员类是叶子节点,老板类下面可以包含子节点。
用户界面如图:
一个类共同的接口:
雇员类的定义:
这里通过IEnumerator对这个节点的子节点进行遍历。
getSalaries() 函数是一个递归的调用,可以计算自身工资和所有子节点工资的总和。
Boss类的定义如下:
Boss类继承了Employee类,因为Boss类本身也是雇员。
在主程序中就可以构建雇员的树形结构了:
这样就完成一个组合模式的对对象的封装。
然后还需要下面一些时间函数:
在这个例子的基础上,我们还可以添加树形结构的双向链表,从而可以进行从叶子节点向上遍历,方便的查找父类信息。
这样对Employee类的改动如下:
这个类中添加了一个指向父类的引用。
这样就可以向上遍历,找到上级领导信息:
组合模式允许定义简单对象和更加复杂的组件对象的类层次结构,这样这些对象就能够以相同的方式呈献给客户端程序。基于这一简易性,客户端就可以更加价单,因为节点和叶子可以被以同样的方式处理。
组合模式还可以让你很容易的添加新类型的组件到集合中,只要这些组件支持相类似的编程接口就可以了。
在树形结构中,访问组合中所有的对象要求有一个简单的单一访问接口,但同时要求能够区分开节点和叶子。在构造组合的时候,我们需要决定哪个节点是元素哪个是叶子。在这里我们可以通过子节点个数进行判断是不是叶子节点。
比如构造一个公司的人事管理系统,经理下面有部门经理,部门经理下面有小组负责人,小组负责人下面有员工这样一个树形结构。在程序里我们需要显示每个人的成本,对于普通员工,一个人的成本就是他的工资,而对于部门经理,他的成本就是他的工资加上手下所有人的工资。
我们需要定义两种类:雇员类和老板类,雇员类是叶子节点,老板类下面可以包含子节点。
用户界面如图:
一个类共同的接口:
using System; using System.Collections ; namespace Composite { /// <summary> /// Summary description for AbstractEmployee. /// </summary> public interface AbstractEmployee { float getSalary(); //get current salary string getName(); //get name bool isLeaf(); //true if leaf void add(string nm, float salary); //add subordinate void add(AbstractEmployee emp); //add subordinate IEnumerator getSubordinates(); //get subordinates AbstractEmployee getChild(); //get child float getSalaries(); //get salaries of all } }
雇员类的定义:
using System; using System.Collections ; namespace Composite { /// <summary> /// Summary description for Employee. /// </summary> public class Employee :AbstractEmployee { protected float salary; protected string name; protected ArrayList subordinates; //------ public Employee(string nm, float salry) { subordinates = new ArrayList(); name = nm; salary = salry; } //------ public float getSalary() { return salary; } //------ public string getName() { return name; } //------ public bool isLeaf() { return subordinates.Count == 0; } //------ public virtual void add(string nm, float salary) { throw new Exception("No subordinates in base employee class"); } //------ public virtual void add(AbstractEmployee emp) { throw new Exception("No subordinates in base employee class"); } //------ public IEnumerator getSubordinates() { return subordinates.GetEnumerator (); } public virtual AbstractEmployee getChild() { return null; } //------ public float getSalaries() { float sum; AbstractEmployee esub; //get the salaries of the boss and subordinates sum = getSalary(); IEnumerator enumSub = subordinates.GetEnumerator() ; while (enumSub.MoveNext()) { esub = (AbstractEmployee)enumSub.Current; sum += esub.getSalaries(); } return sum; } } }
这里通过IEnumerator对这个节点的子节点进行遍历。
getSalaries() 函数是一个递归的调用,可以计算自身工资和所有子节点工资的总和。
Boss类的定义如下:
using System; using System.Collections ; namespace Composite { /// <summary> /// Summary description for Boss. /// </summary> public class Boss:Employee { public Boss(string name, float salary):base(name,salary) { } //------ public Boss(AbstractEmployee emp):base(emp.getName() , emp.getSalary()) { } //------ public override void add(string nm, float salary) { AbstractEmployee emp = new Employee(nm,salary); subordinates.Add (emp); } //------ public override void add(AbstractEmployee emp){ subordinates.Add(emp); } //------ public override AbstractEmployee getChild() { bool found; AbstractEmployee tEmp = null; IEnumerator esub ; if (getName().Equals (getName())) return this; else { found = false; esub = subordinates.GetEnumerator (); while (! found && esub.MoveNext()) { tEmp = (AbstractEmployee)esub.Current; found = (tEmp.getName().Equals(name)); if (! found) { if (! tEmp.isLeaf()) { tEmp = tEmp.getChild(); found = (tEmp.getName().Equals(name)); } } } if (found) return tEmp; else return new Employee("New person", 0); } } } }
Boss类继承了Employee类,因为Boss类本身也是雇员。
在主程序中就可以构建雇员的树形结构了:
private void buildEmployeeList() { prez = new Boss("CEO", 200000); marketVP = new Boss("Marketing VP", 100000); prez.add(marketVP); salesMgr = new Boss("Sales Mgr", 50000); advMgr = new Boss("Advt Mgr", 50000); marketVP.add(salesMgr); marketVP.add(advMgr); prodVP = new Boss("Production VP", 100000); prez.add(prodVP); advMgr.add("Secy", 20000); //add salesmen reporting to sales manager for (int i = 1; i<=5; i++){ salesMgr.add("Sales" + i.ToString(), rand_sal(30000)); } prodMgr = new Boss("Prod Mgr", 40000); shipMgr = new Boss("Ship Mgr", 35000); prodVP.add(prodMgr); prodVP.add(shipMgr); for (int i = 1; i<=3; i++){ shipMgr.add("Ship" + i.ToString(), rand_sal(25000)); } for (int i = 1; i<=4; i++){ prodMgr.add("Manuf" + i.ToString(), rand_sal(20000)); } } //----- private void buildTree() { EmpNode nod; nod = new EmpNode(prez); rootNode = nod; EmpTree.Nodes.Add(nod); addNodes(nod, prez); }
using System; using System.Windows.Forms; namespace Composite { /// <summary> /// Summary description for EmpNode. /// </summary> public class EmpNode:TreeNode { private AbstractEmployee emp; public EmpNode(AbstractEmployee aemp ):base(aemp.getName ()) { emp = aemp; } //----- public AbstractEmployee getEmployee() { return emp; } } }
这样就完成一个组合模式的对对象的封装。
然后还需要下面一些时间函数:
private void EmpTree_AfterSelect(object sender, TreeViewEventArgs e) { EmpNode node; node = (EmpNode)EmpTree.SelectedNode; getNodeSum(node); }
private void getNodeSum(EmpNode node) { AbstractEmployee emp; float sum; emp = node.getEmployee(); sum = emp.getSalaries(); lbSalary.Text = sum.ToString ();
在这个例子的基础上,我们还可以添加树形结构的双向链表,从而可以进行从叶子节点向上遍历,方便的查找父类信息。
这样对Employee类的改动如下:
using System; using System.Collections ; namespace Composite { /// <summary> /// Summary description for Employee. /// </summary> public class Employee :AbstractEmployee { protected float salary; protected string name; protected AbstractEmployee parent; protected ArrayList subordinates; //------ public Employee(AbstractEmployee parnt, string nm, float salry) { subordinates = new ArrayList(); name = nm; salary = salry; parent = parnt; } //------ public AbstractEmployee getBoss() { return parent; } //------ public float getSalary() { return salary; } //------ public string getName() { return name; } //------ public bool isLeaf() { return subordinates.Count == 0; } //------ public virtual void add(string nm, float salary) { throw new Exception("No subordinates in base employee class"); } //------ public virtual void add(AbstractEmployee emp) { throw new Exception("No subordinates in base employee class"); } //------ public IEnumerator getSubordinates() { return subordinates.GetEnumerator (); } public virtual AbstractEmployee getChild() { return null; } //------ public float getSalaries() { float sum; AbstractEmployee esub; //get the salaries of the boss and subordinates sum = getSalary(); IEnumerator enumSub = subordinates.GetEnumerator() ; while (enumSub.MoveNext()) { esub = (AbstractEmployee)enumSub.Current; sum += esub.getSalaries(); } return sum; } } }
这个类中添加了一个指向父类的引用。
这样就可以向上遍历,找到上级领导信息:
private void btShowBoss_Click(object sender, System.EventArgs e) { EmpNode node; node = (EmpNode)EmpTree.SelectedNode; AbstractEmployee emp = node.getEmployee (); string bosses = ""; while(emp != null) { bosses += emp.getName () +"\n"; emp = emp.getBoss(); } MessageBox.Show (null, bosses,"Reporting chain"); }
组合模式允许定义简单对象和更加复杂的组件对象的类层次结构,这样这些对象就能够以相同的方式呈献给客户端程序。基于这一简易性,客户端就可以更加价单,因为节点和叶子可以被以同样的方式处理。
组合模式还可以让你很容易的添加新类型的组件到集合中,只要这些组件支持相类似的编程接口就可以了。
相关文章推荐
- 设计模式C#实现(十一)——组合模式
- 深入浅出学习设计模式(C#实现)-组合模式
- 201802170025->深入浅出设计模式:c#组合模式
- c#设计模式之:组合模式(Composite)
- c#设计模式-组合模式
- 设计模式----组合模式(C#)
- C#设计模式之组合
- 乐在其中设计模式(C#) - 组合模式(Composite Pattern)
- c#设计模式-组合模式
- C#设计模式之组合(Composite)
- 【C#设计模式-组合模式】
- 乐在其中设计模式(C#) - 组合模式(Composite Pattern)
- c#设计模式之组合模式(composition pattern)
- 乐在其中设计模式(C#) - 组合模式(Composite Pattern)
- C#设计模式系列:组合模式(Composite)
- C# 设计模式系列教程-组合模式
- C#设计模式之组合(Composite)
- C#设计模式之九组合模式(Composite Pattern)【结构型】
- C#设计模式——组合模式(Composite Pattern)
- C#设计模式—组合模式