一:什麼是建造模式
建造模式是對象的創建模式【GOF95】。建造模式可以將一個產品的內部表象和產品的生產過程分割開來,從而可以使一個建造過程生成具有不同內部表象的產品對象。
二:引入建造模式
考慮如下問題:我要建造一部設備(Equipment對象),我們希望將這個複雜的對象的構建與其內部表象分離,使得同樣的構建過程可以具有不同內部表象的設備。譬如輸入設備,輸出設備等。不難看出,這種情況下應該使用建造模式。
就Builder模式來說,最重要的當然是Build行爲的抽象。以本例而言,要創建一個Equipment對象,需要Build的是Port和Machine對象,所以我們可以定義兩個Build方法的抽象。
void BuildPort();
void BuildMachine(string machineName);
按照這樣一個原則,我們可以建立如圖17-1所示的類圖。
圖17-1 Builder類的繼承體系
實現代碼如下:
public abstract class EQPBuilder
{
protected Equipment m_equipment;
protected Machine m_machine;
public EQPBuilder()
{
m_equipment = new Equipment();
}
public abstract void BuildPort();
public virtual void BuildMachine(string name)
{
m_machine = new Machine(name);
m_equipment.Name = name;
m_equipment.Machine = m_machine;
}
public Equipment GetEQP()
{
return m_equipment;
}
}
public class InputEQPBuilder:EQPBuilder
{
public override void BuildPort()
{
Port port = new InputPort();
m_equipment.AddPort(port);
}
public override void BuildMachine(string name)
{
base.BuildMachine(name);
m_machine.PortType = "Input";
}
}
public class OutputEQPBuilder:EQPBuilder
{
public override void BuildPort()
{
Port port = new OutputPort();
m_equipment.AddPort(port);
}
public override void BuildMachine(string name)
{
base.BuildMachine(name);
m_machine.PortType = "Output";
}
}
public class IOPutEQPBuilder:EQPBuilder
{
public override void BuildPort()
{
Port inputPort = new InputPort();
Port outputPort = new OutputPort();
m_equipment.AddPort(inputPort);
m_equipment.AddPort(outputPort);
}
public override void BuildMachine(string name)
{
base.BuildMachine(name);
m_machine.PortType = "InputOutput";
}
}
由於Builder子類對於Port對象的創建完全不同,因 此我們將父類EQPBuilder中的CreatePort方法定義爲抽象方法;至於創建Machine對象的CreateMachine方法,則因爲具 有一些共同的邏輯,可以在父類中提供實現,所以被定義爲虛方法,並將相同的邏輯抽象到父類中。EQPBuilder的子類需要重寫父類的 CreateMachine方法,並在調用父類的CreateMachine方法後,根據創建的Port對象的不同,分別設置Machine對象的 PortType值。
此外,在抽象類EQPBuilder中,定義了GetEQP方法,用於返回一個Equipment對象,這個對象其實就是EQPBuilder類型對象所創建的產品。由於各個Builder子類返回Equipment對象的實現邏輯完全一樣,因而被定義爲普通方法。
在 Builder模式的實現中,已經有了Product(產品)角色Equipment類對象,有了Builder(建造者)角色EQPBuilder類對 象,以及它的派生子類。現在還缺少一個Director(指導者)角色,用以引入具體建造者角色,指導完成產品的創建。該角色類似於工廠模式中的工廠對 象。因此,我將其定義爲LCDFactory,便於調用者理解其職能。
public static class LCDFactory
{
public static Equipment CreateEQP(EQPBuilder buider, string name)
{
buider.BuildPort();
buider.BuildMachine(name);
return buider.GetEQP();
}
}
由於LCDFactory類的靜態方法CreateEQP接受的參數是抽象類EQPBuilder,所以指導者角色與建造者角色之間僅存在弱依賴關係,保證了Builder的擴展不會影響產品的創建,類圖如圖17-2所示。
圖17-2 Builder模式的實現類圖
與標準的Builder模式不同,爲了調用方便,我將EQPBuilder類型中的GetEQP方法也封裝到了LCDFactory類中,因此客戶端的調用方式應該如下所示。
class Program
{
static void Main(string[] args)
{
EQPBuilder builder = new InputEQPBuilder();
Equipment eqp = LCDFactory.CreateEQP(builder, "InputMachine");
eqp.Run();
builder = new IOPutEQPBuilder();
eqp = LCDFactory.CreateEQP(builder, "InputOutputMachine");
eqp.Run();
Console.Read();
}
}
三:建造模式的使用情況
在以下情況下應該使用建造模式:
Case1:需要生成的產品對象有複雜的內部結構。
Case2:需要生成的產品對象的屬性相互依賴。
Case3:在對象的創建過程中使用