抽象工廠(Abstract Factory)模式是比工廠模式更高一層的抽象在希望返回對象的幾個相關類中的一個時可以使用該模式每個類都能夠根據需要返回幾個不同的對象換句話說抽象工廠是一個工廠對象其返回幾組類中的一組
更形象的說抽象工廠模式需要存在一個抽象工廠然後每個具體的工廠繼承這個設計好的抽象工廠每個具體工廠可以根據需要返回自己需要的類具體工廠通過抽象工廠返回不同的類
下面舉個具體的例子
在一塊土地上設計一個園地我們可以把園地設計成一年生的植物園也可以設計成菜園或者多年生的植物園不論設計成哪一種園地都會設計到這樣的一些問題哪些植物應該種在邊上哪些植物適宜種在中間哪些植物是喜陰的特性等等
我們設計一個Garden的類作為一個抽象工廠這個類中包含了植物的可能的種類然後實現這個類的具體工廠就可以根據需要生成不同植物的實例
抽象工廠Garden類的設計
[html] view plaincopy using Systemusing SystemDrawing namespace Gardener { /// <summary> /// Summary description for Garden /// </summary> public class Garden { protected Plant center shade borderprotected bool showCenter showShade showBorder//select which ones to display public void setCenter() {showCenter = true} public void setBorder() {showBorder =true} public void setShade() {showShade =true} //draw each plant public void draw(Graphics g) { if (showCenter) centerdraw (g )if (showShade) shadedraw (g )if (showBorder) borderdraw (g )}
在Garden類中可以看到抽象工廠可以包含的Plant類的種類有centershadeborder三種類型
Plant類的設計簡單的給出如下
[html] view plaincopy using Systemusing SystemDrawing
namespace Gardener { /// <summary> /// Summary description for Plant /// </summary> public class Plant { private string nameprivate Brush brprivate Font font
public Plant(string pname) { name = pname //save name font = new Font (Arial )br = new SolidBrush (ColorBlack )} //——public void draw(Graphics g int x int y) { gDrawString (name font br x y)}
Plant類中的draw()方法是用來在顯示區域繪制文字的
Garden這一作為接口的類是抽象工廠其中定義了類的方法繼承了Garden類的具體工廠能夠返回Garden類中規定的類的幾個這裡Garden類規定的返回的類可以有centershadeborder三種類型
在繼承Garden類的子類中可以根據自己的需要返回需要的Plant類下面給出Garden的一個子類的定義VeggieGarden類的定義如下
[html] view plaincopy using System
namespace Gardener { /// <summary> /// Summary description for VeggieGarden /// </summary> public class VeggieGarden Garden { public VeggieGarden() { shade = new Plant(Broccoli)border = new Plant (Peas)center = new Plant (Corn)}
PerennialGarden類的定義如下
[html] view plaincopy using System
namespace Gardener { /// <summary> /// Summary description for PerennialGarden /// </summary> public class PerennialGarden Garden { public PerennialGarden() { shade = new Plant(Astilbe)border = new Plant (Dicentrum)center = new Plant (Sedum)}
AnnualGarden類的定義如下
[html] view plaincopy using Systemusing SystemDrawing
namespace Gardener { /// <summary> /// Summary description for AnnualGarden /// </summary> public class AnnualGarden Garden { public AnnualGarden () { shade = new Plant(Coleus)border = new Plant (Alyssum)center = new Plant (Marigold)}
這三個Garden類的子類都生成了shade border center 三個Plant類型這就是實現了具體工廠通過抽象工廠返回不同的類這裡為了簡便起見讓這三個具體工廠返回的類型都包含三種Plant類型每一個具體工廠返回的shade都不相同即為根據需要返回不同的對象而且三個工廠也可以根據需要返回部分Garden類中規定的Plant類型比如AnnualGarden 可以只返回shade和border而不生成center的實例
我們在圖像狂內部繪制圓圈來表示陰影區並且讓各個植物繪制自己的文字並不是在主窗口中直接繪制而是在主窗口中包含的PictureBox類中添加一個繪圖方法這就要重寫底層空間類的基礎OnPaint事件
[html] view plaincopy using Systemusing SystemCollectionsusing SystemComponentModelusing SystemDrawingusing SystemDatausing SystemWindowsForms
namespace Gardener { /// <summary> /// Summary description for GdPic /// </summary> public class GdPic SystemWindowsFormsPictureBox { /// <summary> /// Required designer variable /// </summary> private SystemComponentModelContainer components = nullprivate Brush brprivate Garden gdenprivate void init () { br = new SolidBrush (ColorLightGray )} public GdPic() { // This call is required by the WindowsForms Form Designer InitializeComponent()init()} public void setGarden(Garden garden) { gden = garden} protected override void OnPaint ( PaintEventArgs pe ){ Graphics g = peGraphicsgFillEllipse (br )if(gden != null)
gdendraw (g)}
/// <summary> /// Clean up any resources being used /// </summary> protected override void Dispose( bool disposing )
{ if( disposing )
{ if(components != null)
{ componentsDispose()} baseDispose( disposing )}
#region Component Designer generated code /// <summary> /// Required method for Designer support do not modify /// the contents of this method with the code editor /// </summary> private void InitializeComponent()
{ // // GdPic //
} #endregion
}
在單選框按鈕事件被觸發後就可以根據按鈕的類型生成不同的具體工廠這樣具體工廠就根據抽象工廠以及自己的需要生成不同的Plant類
[html] view plaincopy private void opAnnual_CheckedChanged(object sender EventArgs e) { setGarden( new AnnualGarden ())} //——private void opVegetable_CheckedChanged(object sender EventArgs e) { setGarden( new VeggieGarden ())} //——private void opPerennial_CheckedChanged(object sender EventArgs e) { setGarden( new PerennialGarden ())} //——private void setGarden(Garden gd) { garden = gd //save current garden gdPicsetGarden ( gd) //tell picture bos gdPicRefresh () //repaint it ckCenterChecked =false //clear all ckBorderChecked = false //check ckShadeChecked = false //boxes }
當某個復選框呗選中時設置某個Plant的可見性然後調用重繪功能在顯示區域繪制文字
[csharp] view plaincopy private void ckCenter_CheckedChanged(object sender SystemEventArgs e) { gardensetCenter ()gdPicRefresh ()} //——private void ckBorder_CheckedChanged(object sender SystemEventArgs e) { gardensetBorder()gdPicRefresh ()} //——private void ckShade_CheckedChanged(object sender SystemEventArgs e) { gardensetShade ()gdPicRefresh ()}
抽象工廠的優點
抽象工廠非常大的優點就是可以非常容易的添加新的子類即具體工廠的類型可以非常容易的添加例如可以添加玫瑰花園或者野花園
抽象工廠的主要目的之一就是隔離所生成的具體類這些類的真正類名被隱藏在工廠內部完全不需要讓客戶端層面知道
雖然抽象工廠生成的所有子類都有共同的基類不過並不能防止這一點即一些子類有著與其他類並不相同的一些方法比如有些子類添加了自己的方法這帶來了在所有子類都會發生的一個問題除非已經知道子類是否支持這些方法否則就不能確定是否能夠調用類的方法
這一問題有兩種解決方法可以在基類中定義所有的方法即使他們並不是總有實際作用
提取一個新的基本接口該接口包含所有需要的方法然後將所有的具體工廠類作為該接口的子類即實現該接口
From:http://tw.wingwit.com/Article/program/net/201311/11929.html