一、Builder模式的緣起(也就是需求)
1、假設創建遊戲中的一個房屋House設施,該房屋的構建由幾個部分組成,且各個部分要富於變化。
2、如果使用最直觀的設計方法,每一個房屋部分的變化,都將導致房屋構建的重新修正......
二、動機
在軟件系統中,有時候面臨着“一個複雜對象”的創建工作,其通常由各個部分的子對象用一定的算法構成,由於需要的變化,這個複雜對象的各個部分經常面臨着劇烈的變化,但是將它們組合在一起的算法卻相對穩定。
如何應對這種變化,如何提供一種“封裝機制”來隔離出“複雜對象各個部分”的變化,從而保持系統中的“穩定構建算法”不隨着需要的變化而變化。
三、類圖
四、代碼
1、Build.cs
namespace Builder
{
public abstract class House
{
}
public abstract class Door
{
}
public abstract class Wall
{
}
public abstract class Windows
{
}
public abstract class Floor
{
}
public abstract class HouseCelling
{
}
public abstract class Builder
{
public abstract void BuildDoor();
public abstract void BuildWall();
public abstract void BuildWindows();
public abstract void BuildFloor();
public abstract void BuildHouseCelling();
public abstract House GetHouse();
}
}
2、RomaHouse.cs
namespace Builder
{
public class RomaHouse:House
{
public RomaHouse()
{
Console.WriteLine("/n建設羅馬式房屋");
}
}
public class RomaDoor : Door
{
public RomaDoor()
{
Console.WriteLine("/n建設羅馬式門");
}
}
public class RomaWall : Wall
{
public RomaWall()
{
Console.WriteLine("/n建設羅馬式牆");
}
}
public class RomaWindows : Windows
{
public RomaWindows()
{
Console.WriteLine("/n建設羅馬式窗");
}
}
public class RomaFloor : Floor
{
public RomaFloor()
{
Console.WriteLine("/n建設羅馬式地板");
}
}
public class RomaHouseCelling : HouseCelling
{
public RomaHouseCelling()
{
Console.WriteLine("/n建設羅馬式屋頂");
}
}
public class RomaHouseBuilder : Builder
{
public override void BuildDoor()
{
Door door = new RomaDoor();
Console.WriteLine("/n羅馬式門建成了");
}
public override void BuildWall()
{
Wall wall = new RomaWall();
Console.WriteLine("/n羅馬式牆建成了");
}
public override void BuildWindows()
{
Windows windows = new RomaWindows();
Console.WriteLine("/n羅馬式窗建成了");
}
public override void BuildFloor()
{
Floor floor = new RomaFloor();
Console.WriteLine("/n羅馬式地板建成了");
}
public override void BuildHouseCelling()
{
HouseCelling housecelling = new RomaHouseCelling();
Console.WriteLine("/n羅馬式屋頂建成了");
}
public override House GetHouse()
{
return new RomaHouse();
}
}
}
3、GameManager.cs
namespace Builder
{
public class GameManager
{
public static House CreateHouse(Builder builder)
{
builder.BuildDoor();
builder.BuildWall();
builder.BuildWindows();
builder.BuildFloor();
builder.BuildHouseCelling();
return builder.GetHouse();
}
}
}
4、Client.cs
namespace Builder
{
class App
{
public static void Main()
{
string builderName = ConfigurationSettings.AppSettings["BuildName"].ToString();
string assemblyName = ConfigurationSettings.AppSettings["BuildAssembly"].ToString();
Assembly assembly = Assembly.Load(assemblyName);
Type t = assembly.GetType(builderName);
Builder builder = (Builder)Activator.CreateInstance(t);
House house = GameManager.CreateHouse(builder);
Console.ReadLine();
}
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="BuildName" value="Builder.RomaHouseBuilder"></add>
<add key="BuildAssembly" value="Builder"></add>
</appSettings>
</configuration>
五、代碼分析
首先看看運行結果:
大家看代碼之後也許會認爲,生成器模式與抽象工廠模式幾乎沒什麼區別,沒錯,確實很相似,現在我來談談不同之處。
首先我們來從代碼談起,大家注意兩種模式最大的不同就是GameManager.cs這個類,生成器模式中的GameManager類中各個子對象都互不相干,由各個子對象來生成一個大的對象;而抽象工廠模式GameManager類中各個對象是耦合的,大家注意到Building類中building(Road road)方法沒有(也許遊戲場景中房屋下面有路)
下面總結一下兩種模式是不同:
生成器模式解決“對象部分”的需求變化,如例中假設房屋裏面加上一個牀,那將是相當方便的,只需要新增一個牀類,然後在GameManager中加上builder.BuildBed()就ok了。
抽象工廠模式解決是“系列對象”的需求變化,如例中只有在道路,房屋,地道,叢林這四種均不會變化的情況下才適用,假設再加一個沙漠或者是海洋什麼的,這種模式就不適用了。
最後說明一點,在App.config中有兩個地方可由用戶配置程序集和類名,main方法中利用反射機制根據程序集和類名實例化一個類對象,這樣就可以很方便地修改房屋的風格(比如當前是Roma風格的,您也可以新增一個China風格的)