設計模式:三種工廠模式

RenshuozZ發表於2019-07-03

三種工廠模式

簡單工廠實現

簡單工廠模式(嚴格來說這不算一種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
     }
}

總結

簡單工廠優點

  • 實現了物件建立和使用的分離,呼叫者可以免除直接建立產品物件的職責,而僅僅"消費"產品。
  • 呼叫者無須知道所建立的具體產品類的類名,只需要知道具體產品類所對應的的引數即可。

    簡單工廠缺點

  • 工廠類集中了所有產品的建立邏輯,職責過重,一旦不能正常工作,整個系統都要受影響。
  • 系統擴充套件困難,一旦新增新產品就不得不修改工廠邏輯,在產品型別較多時,有可能會造成工廠邏輯過於複雜,不利於系統的擴充套件和維護。

工廠優點

  • 工廠方法用於建立客戶所需要的產品,還向客戶隱藏了哪種具體產品類將被例項化這一細節。因此,使用者只需要關心所需產品對應的工廠,無須關心建立細節。
  • 在系統中加入新產品時,無需修改抽象工廠和抽象產品提供的介面,也無須修改客戶端,還無須修改其他的具體工廠和具體產品,而只要加入一個具體工廠和具體產品就可以了。因此,系統的可擴充套件性得到了保證,符合開閉原則。

    工廠缺點

  • 在新增新產品時,需要編寫新的具體產品類,還要提供與之對應的具體工廠類,系統中類的個數將成對增加,一定程度上增加了系統的複雜度。
  • 由於考慮到系統的可擴充套件性,需要引入抽象層,且在實現時可能需要用到反射等技術,增加了系統的實現難度。

抽象工廠優點

  • 隔離了具體類的生成,使得客戶並不需要知道什麼被建立。因為這種隔離,因此更換一個具體工廠就變得相對容易。
  • 當一個產品族中的多個物件被設計稱一起工作時,它能夠保證客戶端始終只使用同一個產品族中的物件。
  • 增加新的產品族很方便,無需修改已有系統,符合開閉原則。

    抽象工廠缺點

  • 增加新的產品等級結構因為需要對原有系統進行較大的修改,甚至需要修改抽象層程式碼,這必然會帶來較大的不便,在這個角度,它違背了開閉(對擴充套件開放,對修改封閉)原則。

下載原始碼

相關文章