2011年12月6日 星期二

設計模式 - Builder

關於 Design Pattern 的 Builder(生成器)模式,有以下幾個特點

1. 將物件的複雜建立過程封裝起來,不讓Client知道

2. 能將複雜的組件建立與組件的操作分開

3. 每個 Builder 都是各自獨立,維護方便

4. 使用相同的建造過程但是產生不同的物件

底下用一個 Java 範例來呈現 Builder 模式 的範例

首先一個電腦 (AbstractComputer) 會由很多組件(AbstractComputerItem)所組成

這些組件例如以下
處理器(AbstractCpu)
螢幕(AbstractMonitor)
應用程式(AbstractApp)
硬碟(AbstractDisk)
鍵盤(AbstractKeyboard)

到這邊先來看一下這幾隻程式吧

AbstractComputerItem.java
public abstract class AbstractComputerItem 
{
 private String name;  //組件的名稱
 public AbstractComputerItem(String name){
  this.name = name;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
}
接下來是各組件...
public abstract class AbstractCpu extends AbstractComputerItem {
 public AbstractCpu(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }
}
public abstract class AbstractMonitor extends AbstractComputerItem {
 public AbstractMonitor(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }
}
public abstract class AbstractApp extends AbstractComputerItem {
 public AbstractApp(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }
}
public abstract class AbstractDisk extends AbstractComputerItem {
 public AbstractDisk(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }
}
public abstract class AbstractKeyboard extends AbstractComputerItem {
 public AbstractKeyboard(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }
}
public abstract class AbstractComputer 
{
 private AbstractMonitor monitor;
 private AbstractCpu cpu;
 private AbstractApp app;
 private AbstractKeyboard keyboard;
 private AbstractDisk disk;
        
        //以下我省略 getter/setter
}
接下來電腦(AbstractComputer)會為抽像類別 主要是電腦有可能會是某間廠商的
例如 筆電中 ASUS 和 ACER

也就如下...(以下只舉一個例子.. AcerComputer.java省略...

AsusComputer.java
public class AsusComputer extends AbstractComputer 
{
 
}
Builder 主要就是要將多個部件裝配到一個物件中(ASUS或ACER的電腦) 所以

這裡呼應了 Builder 透過同樣的建構方法(不論是Asus或是Acer都需要組裝CPU,螢幕,...)


產生出不同的表現實體(AsusComputer 或 AcerComputer)


言下之意就是會有一個ASUS筆電的Builder 和 ACER筆電的Builder (AsusBuilder,AcerBuilder)


以下只列舉一個說明

ComputerBuilder.java
//一個定義共通方法的 Builder 抽像類別
public abstract class ComputerBuilder 
{
 public abstract void buildBase();  //產生相應的實體
 public abstract void addMonitor(AbstractMonitor moniter); //組裝螢幕
 public abstract void addCpu(AbstractCpu cpu);  //組裝處理器
 public abstract void addApp(AbstractApp app);  //組裝應用程式
 public abstract void addKeyboard(AbstractKeyboard keyboard); //..略
 public abstract void addDisk(AbstractDisk disk);  //.. 略
 public abstract AbstractComputer getComputer();
}
AsusBuilder.java
public class AsusBuilder extends ComputerBuilder 
{
 private AbstractComputer asusComputer;  
 @Override
 public void buildBase() {  //產生一個 AsusComputer 的實體
  // TODO Auto-generated method stub
  this.asusComputer = new AsusComputer(); 
 }
 
 @Override
        //取得建構完後的 AsusComputer 
 public AbstractComputer getComputer() {  
  // TODO Auto-generated method stub
  return this.asusComputer;
 }

 @Override
 public void addMonitor(AbstractMonitor monitor) {
  // TODO Auto-generated method stub
  this.asusComputer.setMonitor(monitor);
 }

 @Override
 public void addCpu(AbstractCpu cpu) {
  // TODO Auto-generated method stub
  this.asusComputer.setCpu(cpu);
 }

 @Override
 public void addApp(AbstractApp app) {
  // TODO Auto-generated method stub
  this.asusComputer.setApp(app);
 }

 @Override
 public void addKeyboard(AbstractKeyboard keyboard) {
  // TODO Auto-generated method stub
  this.asusComputer.setKeyboard(keyboard);
 }

 @Override
 public void addDisk(AbstractDisk disk) {
  // TODO Auto-generated method stub
  this.asusComputer.setDisk(disk);
 }
}
完成之後就剩下最後一項了 也就是所謂的導演 "Director"
由他來負責指揮 Builder 來建構整台電腦(封裝 Builder 整個的操作過程)
public class ComputerDirector 
{
 private ComputerBuilder cb;  //reference 一個 Builder
 
 public ComputerDirector(ComputerBuilder cb){
  this.cb = cb;
 }
 
 public AbstractComputer produceComputer(List items){
  cb.buildBase();  //create instance
                //依序將挑出各組件並透過Builder組成電腦
  for(Iterator it = items.iterator();it.hasNext();){
   AbstractComputerItem item = (AbstractComputerItem)it.next();
   if(item instanceof AbstractCpu){
    cb.addCpu((AbstractCpu)item);
   }else if(item instanceof AbstractDisk){
    cb.addDisk((AbstractDisk)item);
   }else if(item instanceof AbstractMonitor){
    cb.addMonitor((AbstractMonitor)item);
   }else if(item instanceof AbstractApp){
    cb.addApp((AbstractApp)item);
   }else if(item instanceof AbstractKeyboard){
    cb.addKeyboard((AbstractKeyboard)item);
   }else{
    //throw a exception .. computer do not support this item
   }
  }
  return cb.getComputer();
 }
}
到這邊就可以在 Client 透過 Director 建立一個 AsusComputer 了
//...
//items 表示了所有的零組件
private List items = new ArrayList();
//包含以下的所有 ASUS 的產品
items.add(new AsusCpu("Asus's cpu"));
items.add(new AsusMonitor("Asus's monitor"));
items.add(new AsusApp("Asus's application"));
items.add(new AsusDisk("Asus's disk"));
items.add(new AsusKeyboard("Asus's keyboard"));

//呼叫 Director 並告訴他目前要建立的是 AsusComputer 所以傳入相對應的 Builder 
ComputerDirector director = new ComputerDirector(new AsusBuilder());
AbstractComputer asus = director.produceComputer(items);  //開始組裝電腦
//完成...

最後付張 Builder 設計模式的類別圖簡單介紹一下



Director 就是上面程式的 ComputerDirector.java 

由他負責來協調 Builder 建構相對應的物件

Builder 就是上面程式的 ComputerBuilder.java

ConcreteBuilder 則是以上的 AsusBuilder.java

Product 當然就是 AsusComputer.java 了

沒有留言:

張貼留言