三種工廠模式
簡單工廠實現
簡單工廠模式(嚴格來說這不算一種Gof的設計模式,更像是一種程式設計習慣)屬於類的建立型模式,又叫做靜態工廠方法模式。通過專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有相同的父類,應用繼承將決定工廠的生產什麼產品的決定權直接交到了客戶手中,然後客戶在輸入自己的需求,得到最終的結果。
運用簡單工廠模式實現生產pizza的業務場景。
/// <summary>
/// pizza建立工廠
/// </summary>
public class PizzaFactory
{
public static Pizza CreatePizza(string pizzaType)
{
switch (pizzaType)
{
case "Cheese":
return new CheesePizza();
case "ApplePie":
return new ApplePiePizza();
default:
return new SomeOtherPizza();
}
}
}
public abstract class Pizza
{
public string Name { get; set; }
public void Prepare()
{
Console.WriteLine($"Preparing {Name}");
}
public void Cut()
{
Console.WriteLine($"Cutting the {Name}");
}
public void Bake()
{
Console.WriteLine($"Baking the {Name}");
}
public void Box()
{
Console.WriteLine($"Boxing the {Name}");
}
}
public class ApplePiePizza : Pizza
{
public ApplePiePizza()
{
Name = "ApplePie";
}
}
public class CheesePizza : Pizza
{
public CheesePizza()
{
Name = "Cheese";
}
}
public class SomeOtherPizza : Pizza
{
public SomeOtherPizza()
{
Name = "Other";
}
}
//呼叫
class Program
{
static void Main(string[] args)
{
Pizza pizza = PizzaFactory.CreatePizza("cheese");
pizza.Box();
}
}
//輸出:
//Preparing Cheese
//Cutting the Cheese
//Baking the Cheese
//Boxing the Cheese
簡單工廠模式實現了生成Pizza類的程式碼跟客戶端程式碼分離,在工廠類中你可以新增所需的生成Pizza的邏輯程式碼,但是,簡單工廠並不符合“開放-封閉”原則(對擴充套件開放,對修改關閉),如果要加一種型別VeggiePizza,你就要修改工廠類裡面的生成產品的程式碼,在這裡你就要增加Swich-Case。對於這個問題,我們的工廠方法模式就可以解決這個問題。
工廠模式
運用工廠模式實現生產pizza的業務場景。
/// <summary>
/// 工廠介面
/// </summary>
interface IFactory
{
Pizza CreatePizza();
}
/// <summary>
/// CheesePizza工廠方法
/// </summary>
public class CheesePizzaFactory : IFactory
{
public Pizza CreatePizza()
{
return new CheesePizza();
}
}
/// <summary>
/// ApplePiePizza工廠方法
/// </summary>
public class ApplePiePizzaFactory : IFactory
{
public Pizza CreatePizza()
{
return new ApplePiePizza();
}
}
class Program
{
static void Main(string[] args)
{
IFactory factory = new CheesePizzaFactory();
Pizza cheesePizza = factory.CreatePizza();
cheesePizza.Prepare();
cheesePizza.Cut();
cheesePizza.Bake();
cheesePizza.Box();
//輸出:
//Preparing Cheese
//Cutting the Cheese
//Baking the Cheese
//Boxing the Cheese
}
}
工廠模式中我們通過對應的工廠類來生成對應的Pizza,在這裡符合“開閉”原則,無論加多少Pizza類,我們都不用修改原來類中的程式碼,而是通過增加工廠類來實現。但是這還是有缺點的,如果產品Pizza類過多,我們就要生成很多的工廠類。假如我們要實現的產品介面不止一個,也就是有多個產品介面,不同產品介面有對應的產品族。什麼是產品族呢?簡單的理解就是,不同型別的Pizza會在不同的地區會有不同的準備方式,以材料(麵糰Dough,果醬Sauce)的不同而變幻口味等,同地區不同型別的Pizza可以組成一個產品族。對於這種情況我們可以採用抽象工廠模式。
抽象工廠模式
運用工廠模式實現生產pizza的業務場景。
/// <summary>
/// 麵糰
/// </summary>
public interface Dough
{
void Dough();
}
/// <summary>
/// 紐約麵糰
/// </summary>
public class NYDough : Dough
{
public void Dough()
{
Console.WriteLine("NYDough");
}
}
/// <summary>
/// 芝加哥麵糰
/// </summary>
public class ChicagoDough : Dough
{
public void Dough()
{
Console.WriteLine("ChicagoDough");
}
}
/// <summary>
/// 果醬
/// </summary>
public interface Sauce
{
void Sauce();
}
/// <summary>
/// 紐約果醬
/// </summary>
public class NYSauce : Sauce
{
public void Sauce()
{
Console.WriteLine("NYSauce");
}
}
/// <summary>
/// 芝加哥果醬
/// </summary>
public class ChicagoSauce : Sauce
{
public void Sauce()
{
Console.WriteLine("ChicagoSauce");
}
}
/// <summary>
/// 建造披薩原料工廠 介面
/// </summary>
public interface IPizzaIngredientFactory
{
Dough CreateDough();
Sauce CreateSauce();
}
/// <summary>
/// 紐約披薩工廠
/// </summary>
public class NYPizzaIngredientFactory : IPizzaIngredientFactory
{
public Dough CreateDough()
{
return new NYDough();
}
public Sauce CreateSauce()
{
return new NYSauce();
}
}
/// <summary>
/// 芝加哥披薩工廠
/// </summary>
public class ChicagoPizzaIngredientFactory : IPizzaIngredientFactory
{
public Dough CreateDough()
{
return new ChicagoDough();
}
public Sauce CreateSauce()
{
return new ChicagoSauce();
}
}
public abstract class Pizza
{
public string Name { get; set; }
/// <summary>
/// 麵糰
/// </summary>
public Dough Dough { get; set; }
/// <summary>
/// 醬汁
/// </summary>
public Sauce Sauce { get; set; }
public abstract void Prepare();
public void Cut()
{
Console.WriteLine($"Cutting the {Name}");
}
public void Bake()
{
Console.WriteLine($"Baking the {Name}");
}
public void Box()
{
Console.WriteLine($"Boxing the {Name}");
}
}
public class ApplePiePizza : Pizza
{
IPizzaIngredientFactory _pizzaIngredientFactory;
public ApplePiePizza(IPizzaIngredientFactory pizzaIngredient)
{
this._pizzaIngredientFactory = pizzaIngredient;
Name = "ApplePie";
}
public override void Prepare()
{
Console.WriteLine($"Preparing { Name}");
Dough = _pizzaIngredientFactory.CreateDough();
Dough.Dough();
Sauce = _pizzaIngredientFactory.CreateSauce();
Sauce.Sauce();
}
}
public class CheesePizza : Pizza
{
IPizzaIngredientFactory _pizzaIngredientFactory;
public CheesePizza(IPizzaIngredientFactory pizzaIngredient)
{
this._pizzaIngredientFactory = pizzaIngredient;
Name = "Cheese";
}
public override void Prepare()
{
Console.WriteLine($"Preparing { Name}");
Dough = _pizzaIngredientFactory.CreateDough();
Dough.Dough();
Sauce = _pizzaIngredientFactory.CreateSauce();
Sauce.Sauce();
}
}
public class SomeOtherPizza : Pizza
{
public SomeOtherPizza()
{
Name = "Other";
}
public override void Prepare()
{
throw new NotImplementedException();
}
}
// <summary>
/// 工廠介面
/// </summary>
interface IFactory
{
Pizza CreatePizza(IPizzaIngredientFactory pizzaIngredientFactory);
}
/// <summary>
/// CheesePizza工廠方法
/// </summary>
public class CheesePizzaFactory : IFactory
{
public Pizza CreatePizza(IPizzaIngredientFactory pizzaIngredientFactory)
{
return new CheesePizza(pizzaIngredientFactory);
}
}
/// <summary>
/// ApplePiePizza工廠方法
/// </summary>
public class ApplePiePizzaFactory : IFactory
{
public Pizza CreatePizza(IPizzaIngredientFactory pizzaIngredientFactory)
{
return new ApplePiePizza(pizzaIngredientFactory);
}
}
//呼叫
class Program
{
static void Main(string[] args)
{
IPizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();
IFactory factory = new CheesePizzaFactory();
Pizza cheesePizza = factory.CreatePizza(pizzaIngredientFactory);
cheesePizza.Prepare();
cheesePizza.Cut();
cheesePizza.Bake();
cheesePizza.Box();
//輸出:
//Preparing Cheese
//NYDough
//NYSauce
//Cutting the Cheese
//Baking the Cheese
//Boxing the Cheese
}
}
總結
簡單工廠優點
- 實現了物件建立和使用的分離,呼叫者可以免除直接建立產品物件的職責,而僅僅"消費"產品。
呼叫者無須知道所建立的具體產品類的類名,只需要知道具體產品類所對應的的引數即可。
簡單工廠缺點
- 工廠類集中了所有產品的建立邏輯,職責過重,一旦不能正常工作,整個系統都要受影響。
系統擴充套件困難,一旦新增新產品就不得不修改工廠邏輯,在產品型別較多時,有可能會造成工廠邏輯過於複雜,不利於系統的擴充套件和維護。
工廠優點
- 工廠方法用於建立客戶所需要的產品,還向客戶隱藏了哪種具體產品類將被例項化這一細節。因此,使用者只需要關心所需產品對應的工廠,無須關心建立細節。
在系統中加入新產品時,無需修改抽象工廠和抽象產品提供的介面,也無須修改客戶端,還無須修改其他的具體工廠和具體產品,而只要加入一個具體工廠和具體產品就可以了。因此,系統的可擴充套件性得到了保證,符合開閉原則。
工廠缺點
- 在新增新產品時,需要編寫新的具體產品類,還要提供與之對應的具體工廠類,系統中類的個數將成對增加,一定程度上增加了系統的複雜度。
由於考慮到系統的可擴充套件性,需要引入抽象層,且在實現時可能需要用到反射等技術,增加了系統的實現難度。
抽象工廠優點
- 隔離了具體類的生成,使得客戶並不需要知道什麼被建立。因為這種隔離,因此更換一個具體工廠就變得相對容易。
- 當一個產品族中的多個物件被設計稱一起工作時,它能夠保證客戶端始終只使用同一個產品族中的物件。
增加新的產品族很方便,無需修改已有系統,符合開閉原則。
抽象工廠缺點
增加新的產品等級結構因為需要對原有系統進行較大的修改,甚至需要修改抽象層程式碼,這必然會帶來較大的不便,在這個角度,它違背了開閉(對擴充套件開放,對修改封閉)原則。