2013年10月16日 星期三

Design Pattern : Composite

Design Pattern : Composite

Composite的定義請參考Wiki
簡而言之,就是可新增、刪除、瀏覽每個節點的樹狀結構。

比如說老闆需要將車廠的車子做一張分類表:
【類型(如轎車休旅車)】【系列(如喜美FOCUS)】【型號】

這時候就可以用Composite pattern去實作。

1.  我們先實作房車類別(RV

public class Rv
{
  
/// <summary>
   ///
階層
  
/// </summary>
  
private int level;
  
/// <summary>
   ///
名稱
  
/// </summary>
  
private String name;
  
/// <summary>
   ///
子節點
  
/// </summary>
  
private List<Rv> carList = new List<Rv>();
  
  
public Rv(String _name, int _level=0)
   {
     
this.level = _level;
     
this.name = _name;
   }
  
public void GetInfo()
   {
     
if (this.carList.Count > 0)
      {
        
///顯示此階層訊息
        
this.PrintInfo();
        
///往下巡覽
        
foreach (Rv car in carList)
         {
            car.GetInfo();
         }
      }
     
else
     
{
        
this.PrintInfo();
      }
   }
  
private void PrintInfo()
   {
     
Console.WriteLine(
         
String.Format("Level:{0} {1}", this.level, this.name));
   }
  
public void Add(Rv _car)
   {
     carList.Add(_car);
   }
  
public void Remove(Rv _car)
   {
     carList.Remove(_car);
   }
}

u  新增節點:Add
u  刪除節點:Remove
u  尋覽:GetInfo

2.  主程式:
///Root
Rv RvSeries = new Rv("房車系列", _level: 0);
///First level
Rv focusSeries = new Rv("FocusSeries", _level: 1);
Rv civicSeries = new Rv("CivicSeries", _level: 1);
///Second level
Rv focus4D = new Rv("Focus四門", _level: 2);
Rv focus5D = new Rv("Focus五門", _level: 2);
Rv civic8 = new Rv("Civic八代", _level: 2);
Rv civic9 = new Rv("Civic九代", _level: 2);
try
{
  
///Add Level2
  
focusSeries.Add(focus4D);
   focusSeries.Add(focus5D);
   civicSeries.Add(civic8);
   civicSeries.Add(civic9);
  
///Add Level1
  
RvSeries.Add(focusSeries);
   RvSeries.Add(civicSeries);
  
///Remove
  
civicSeries.Remove(civic8);
  
///Browse
   RvSeries.GetInfo();
}


結果
Composite -----------
Level:0
房車系列
Level:1 FocusSeries
Level:2 Focus
四門
Level:2 Focus
五門
Level:1 CivicSeries
Level:2 Civic
九代

3.  以上的程式碼會違反DIP依賴倒置原則,所以下面會將AddRemoveGetInfo(巡覽)抽象化。
4.  新增一個abstract class : CarSeries

public abstract class CarSeries
{
  
/// <summary>
   ///
階層
  
/// </summary>
  
protected int level;
  
/// <summary>
   ///
名稱
  
/// </summary>
  
protected String name;
  
/// <summary>
   ///
子節點
  
/// </summary>
  
protected List<CarSeries> carList = new List<CarSeries>();
  
   public CarSeries(String _name, int _level)
   {
     
this.name = _name;
     
this.level = _level;
   }
  
public abstract void GetInfo();
  
public abstract void Add(CarSeries car);
  
public abstract void Remove(CarSeries car);
}


5.  建立繼承CarSeries子類別:Suv

public class Suv : CarSeries
{
  
public Suv(String _name, int _level): base(_name, _level)
   {
   }
  
public override void GetInfo()
   {
    
if (this.carList.Count > 0)
     {
       
///顯示此階層訊息
       
this.PrintInfo();
       
///往下巡覽
       
foreach (CarSeries car in carList)
        {
            car.GetInfo();
        }
     }
    
else
    
{
       
this.PrintInfo();
     }
   }


  
private void PrintInfo()
   {

     
Console.WriteLine(
         
String.Format("Level:{0} {1}", this.level, this.name));
   }

  
public override void Add(CarSeries _car)
   {

      this
.carList.Add(_car);
   }
  
public override void Remove(CarSeries _car)
   {
     
this.carList.Remove(_car);
   }
}


6.  主程式:

///
Root
CarSeries SuvSeries = new Suv("休旅車系列", _level:0);
///First level
CarSeries crvSeries = new Suv("CrvSeries", _level: 1);
CarSeries rxSeries = new Suv("RxSeries", _level: 1);
///Second level
CarSeries crv4 = new Suv("CRV四代", _level: 2);
CarSeries crv5 = new Suv("CRV五代", _level: 2);
CarSeries rx100 = new Suv("RX100", _level: 2);
CarSeries rX370 = new Suv("RX370", _level: 2);
try
{
  
///Add Level2
  
crvSeries.Add(crv4);
   crvSeries.Add(crv5);
   rxSeries.Add(rx100);
   rxSeries.Add(rX370);
  ///Add Level1
  
SuvSeries.Add(crvSeries);
   SuvSeries.Add(rxSeries);
  
///Remove
  
rxSeries.Remove(rx100);
  
///Browse
  
SuvSeries.GetInfo();
}

結果:
Composite improved---
Level:0
休旅車系列
Level:1 CrvSeries
Level:2 CRV
四代
Level:2 CRV
五代
Level:1 RxSeries
Level:2 RX370


7.  結束

沒有留言:

張貼留言