当前位置:首页>>ASP.NET教程>>Asp.NET综合技巧>>.NET中的设计模式三:组合模式
.NET中的设计模式三:组合模式
2009/11/8 13:19:18
组合模式(Composite)是一种“结构型”模式(Structural)。结构型模式涉及的对象为两个或两个以上,表示对象之间的活动,与对象的结构有关。

先举一个组合模式的小小例子:



如图:系统中有两种Box:Game Box和Internet Box,客户需要了解者两个类的接口分别进行调用。为了简化客户的工作,创建了XBox类,程序代码如下:

GameBox的代码:

public class GameBox

{

public void PlayGame()

{

Console.WriteLine("plaly game");

}

}


InternetBox的代码:

public class InternetBox

{

public void ConnectToInternet()

{

Console.WriteLine("connect to internet");

}

public void GetMail()

{

Console.WriteLine("check email");

}

}


XBox的代码:

public class XBox

{

private GameBox mGameBox=null;

private InternetBox mInternetBox=null;



public XBox()

{

mGameBox = new GameBox();

mInternetBox = new InternetBox();

}

public void PlayGame()

{

mGameBox.PlayGame();

}

public void ConnectToInternet()

{

mInternetBox.ConnectToInternet();

}

public void GetMail()

{

mInternetBox.GetMail();

}

}


XBox中封装了GameBox和InternetBox的方法,这样,用户面对的情况就大大的简化了,调用的代码如下:

public class CSComposite

{

static void Main (string[] args)

{

XBox x = new XBox();

Console.WriteLine("PlayGame!");

x.PlayGame();

Console.WriteLine();



Console.WriteLine("Internet Play Game!");

x.ConnectToInternet();

x.PlayGame();

Console.WriteLine();



Console.WriteLine("E-Mail!");

x.GetMail();

}

}


可以看见,用户只需要了解XBox的接口就可以了。

组合模式的应用例子

组合模式适用于下面这样的情况:两个或者多个类有相似的形式,或者共同代表某个完整的概念,外界的用户也希望他们合而为一,就可以把这几个类“组合”起来,成为一个新的类,用户只需要调用这个新的类就可以了。

下面举一个例子说明Composite模式的一个实际应用。下面的Class视图:



Employee类是AbstractEmployee接口的一个实现,Boss类是Employee的一个子类,EmpNode是从树视图的TreeNode类继承而来的。我们先看看代码:

AbstractEmployee,这是一个接口,提供下列方法:

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

}


Employee类是AbstractEmployee接口的一个实现

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;

}

}


从Employee接口和他的一个实现来看,下面很可能要将这个类型的数据组合成一个树的结构。

Boss类是Employee类的派生,他重载了Employee类的add和getChild方法:

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; <