設計模式:三種工廠模式

三種工廠模式

簡單工廠實現

簡單工廠模式(嚴格來講這不算一種Gof的設計模式,更像是一種編程習慣)屬於類的建立型模式,又叫作靜態工廠方法模式。經過專門定義一個類來負責建立其餘類的實例,被建立的實例一般都具備相同的父類,應用繼承將決定工廠的生產什麼產品的決定權直接交到了客戶手中,而後客戶在輸入本身的需求,獲得最終的結果。git

運用簡單工廠模式實現生產pizza的業務場景。github

/// <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能夠組成一個產品族。對於這種狀況咱們能夠採用抽象工廠模式。ide

抽象工廠模式

運用工廠模式實現生產pizza的業務場景。this

/// <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
     }
}

總結

簡單工廠優勢

  • 實現了對象建立和使用的分離,調用者能夠免除直接建立產品對象的職責,而僅僅"消費"產品。
  • 調用者無須知道所建立的具體產品類的類名,只須要知道具體產品類所對應的的參數便可。設計

    簡單工廠缺點

  • 工廠類集中了全部產品的建立邏輯,職責太重,一旦不能正常工做,整個系統都要受影響。
  • 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能會形成工廠邏輯過於複雜,不利於系統的擴展和維護。code

工廠優勢

  • 工廠方法用於建立客戶所須要的產品,還向客戶隱藏了哪一種具體產品類將被實例化這一細節。所以,用戶只須要關心所需產品對應的工廠,無須關心建立細節。
  • 在系統中加入新產品時,無需修改抽象工廠和抽象產品提供的接口,也無須修改客戶端,還無須修改其餘的具體工廠和具體產品,而只要加入一個具體工廠和具體產品就能夠了。所以,系統的可擴展性獲得了保證,符合開閉原則。對象

    工廠缺點

  • 在添加新產品時,須要編寫新的具體產品類,還要提供與之對應的具體工廠類,系統中類的個數將成對增長,必定程度上增長了系統的複雜度。
  • 因爲考慮到系統的可擴展性,須要引入抽象層,且在實現時可能須要用到反射等技術,增長了系統的實現難度。繼承

抽象工廠優勢

  • 隔離了具體類的生成,使得客戶並不須要知道什麼被建立。由於這種隔離,所以更換一個具體工廠就變得相對容易。
  • 當一個產品族中的多個對象被設計稱一塊兒工做時,它可以保證客戶端始終只使用同一個產品族中的對象。
  • 增長新的產品族很方便,無需修改已有系統,符合開閉原則。

    抽象工廠缺點

  • 增長新的產品等級結構由於須要對原有系統進行較大的修改,甚至須要修改抽象層代碼,這必然會帶來較大的不便,在這個角度,它違背了開閉(對擴展開放,對修改封閉)原則。

下載源碼

相關文章
相關標籤/搜索