用C# (.NET Core) 实现抽象工厂设计模式
本文的概念性內(nèi)容來自深入淺出設(shè)計模式一書.上一篇文章講了簡單工廠和工廠方法設(shè)計模式 使用的是披薩店的例子. 文將繼續(xù)使用這個例子, 這里要用到抽象工廠.
披薩店的需求變更
現(xiàn)在披薩店在各地授權(quán)了很多連鎖分店, 但是有的分店偷工減料, 使用劣質(zhì)原料代替標(biāo)準(zhǔn)原料.
披薩店老板現(xiàn)在就是想解決這個問題.
原料的一致性問題
首先如何保證原料的質(zhì)量問題? 可以建立一個工廠生產(chǎn)原料, 然后把原料分發(fā)到各地的授權(quán)店.
然后還有一個原料的一致性問題, 例如紐約的番茄醬和芝加哥的番茄醬可能有點不同, 所以它們各自需要一套原料.
也就是說各地的披薩是使用相同的原料, 但是每種原料在各地可能會存在差異(不同的實現(xiàn)).
這就是紐約, 芝加哥和加州各自的原料家族.
建立原料工廠
接下來就是建立原料工廠, 這些工廠將負(fù)責(zé)為各自的家族(地點)創(chuàng)建原料.
首先是工廠的接口:
然后我們要做下面這些內(nèi)容:
為每個地區(qū)創(chuàng)建一個工廠 (實現(xiàn)PizzaIngredientFactory接口及其方法)
實現(xiàn)一些原料的類, 它們可以唄工廠使用, 其中某些原料可以跨地區(qū)共享
最后我們把上面這些整合到PizzaStore里面.
紐約的原料工廠:
就是實現(xiàn)接口, 返回本地需要的原料而已.
修改Pizza抽象類:
這里我們把Prepare()方法(準(zhǔn)備原料)改成抽象的了, 其它的保持不變.
接下來需要為各地創(chuàng)建不同風(fēng)格的披薩了. 現(xiàn)在各地披薩店的原料都是從工廠送來的, 就不能使用劣質(zhì)原料代替了.
之前使用工廠方法模式時, 我們?yōu)槊總€地點創(chuàng)建了不同風(fēng)格的披薩, 例如 NYCheesePizza, ChicagoCheesePizza. 你可以看一下這兩個類, 它們里面只有原料部分(都是同樣的原料, 但是各地風(fēng)格不同)是不同的.
所以實際上, 我們不需要為每個地點創(chuàng)建不同風(fēng)格的披薩, 原料工廠將會替我們處理各地風(fēng)格披薩原料不同這種情況.
例如奶酪披薩只需要一個類就可以:
為了創(chuàng)建奶酪披薩, 在其構(gòu)造函數(shù)里面?zhèn)魅朐瞎S為它提供原料即可.
在prepare()方法里面準(zhǔn)備的原料都是工廠來提供的.
使用哪些地區(qū)/風(fēng)格的原料由工廠決定, 披薩類本身并不關(guān)心, 它只需知道怎么制作披薩就行.
這樣披薩類和各地區(qū)的原材料就解耦了.
綜上, 就是一句話:
原料由工廠提供.
可以再看看另外一個披薩的例子:
修改各地的披薩店
紐約的披薩店現(xiàn)在和紐約的原料工廠組合在一起, 這樣它就可以產(chǎn)出紐約風(fēng)格的披薩了.
在創(chuàng)建披薩的時候把原料工廠傳進去為披薩提供原料.
到目前位置, 我們做了什么?
我們提供了一種可以為披薩提供一族原料的工廠, 這個工廠就叫做抽象工廠.
抽象工廠為創(chuàng)建某一家族的產(chǎn)品提供接口(interface), 針對這個接口編程, 就可以實現(xiàn)從具體生產(chǎn)產(chǎn)品的工廠解耦.
這樣做就允許我們?yōu)椴煌纳舷挛氖褂貌煌瑢崿F(xiàn)的工廠了.
因為我們的代碼是從實際產(chǎn)品解耦的, 我們就可以通過替換工廠來取得不同風(fēng)格的產(chǎn)品了.
梳理一下整個流程
1. 創(chuàng)建紐約的披薩店:
2. 下訂單買披薩
3. orderPizza方法調(diào)用創(chuàng)建披薩的方法:
到這, 代碼都沒有變化.
4.創(chuàng)建披薩的時候, 使用原料工廠:
5. 披薩的準(zhǔn)備工序里是由工廠來提供原料:
6. 按照其他工序加工并返回披薩.
抽象工廠定義
抽象工廠設(shè)計模式提供了一個接口, 這個接口可以創(chuàng)建一族相關(guān)或依賴的對象而無需指明它們具體的類.
下面是類圖:
對應(yīng)披薩店的圖:
工廠方法和抽象工廠的比較
工廠方法是通過繼承來實現(xiàn)創(chuàng)建對象工作的. 而抽象工廠則是通過組合的方法.
工廠方法是讓子類來創(chuàng)建對象, 客戶只需要知道抽象類, 子類做具體的實現(xiàn), 解耦.
抽象工廠提供了一個可以創(chuàng)建一族產(chǎn)品的抽象類, 這個類的實現(xiàn)類/子類決定產(chǎn)品是如何產(chǎn)出的, 也是解耦.
抽象工廠的優(yōu)點是: 可以創(chuàng)建一族相關(guān)的產(chǎn)品. 缺點是它的接口比較大, 如果添加產(chǎn)品了需要改接口.
而工廠方法只負(fù)責(zé)生產(chǎn)一個產(chǎn)品.
抽象工廠也經(jīng)常使用工廠方法來實現(xiàn)具體的工廠.
而工廠方法也經(jīng)常使用抽象的創(chuàng)造者, 它來使用子類創(chuàng)造出的具體產(chǎn)品.
工廠方法:
抽象工廠:
總結(jié)
C#/.NET Core代碼實現(xiàn)
?原料接口:
namespace AbstractFactoryPattern.Abstractions
{
? ? public interface IGredient
? ? {
? ? ? ? string Name { get; }
? ? }
}
namespace AbstractFactoryPattern.Abstractions
{
? ? public interface ICheese: IGredient
? ? {
? ? }
}
namespace AbstractFactoryPattern.Abstractions
{
? ? public interface IClams: IGredient
? ? {
? ? }
}
namespace AbstractFactoryPattern.Abstractions
{
? ? public interface IDough: IGredient
? ? {
? ? }
}
namespace AbstractFactoryPattern.Abstractions
{
? ? public interface ISauce: IGredient
? ? {
? ? }
}
原料工廠接口:
namespace AbstractFactoryPattern.Abstractions
{
? ? public interface IPizzaIngredientFactory
? ? {
? ? ? ? IDough CreateDough();
? ? ? ? ICheese CreateCheese();
? ? ? ? IClams CreateClams();
? ? ? ? ISauce CreateSauce();
? ? }
}
披薩店抽象類:
namespace AbstractFactoryPattern.Abstractions
{
? ? public abstract class PizzaStore
? ? {
? ? ? ? public Pizza OrderPizza(string type)
? ? ? ? {
? ? ? ? ? ? var pizza = CreatePizza(type);
? ? ? ? ? ? pizza.Prepare();
? ? ? ? ? ? pizza.Bake();
? ? ? ? ? ? pizza.Cut();
? ? ? ? ? ? pizza.Box();
? ? ? ? ? ? return pizza;
? ? ? ? }
? ? ? ? protected abstract Pizza CreatePizza(string type);
? ? }
}
披薩抽象類:
using System;
namespace AbstractFactoryPattern.Abstractions
{
? ? public abstract class Pizza
? ? {
? ? ? ? public string Name { get; set; }
? ? ? ? public IDough Dough { get; protected set; }
? ? ? ? public ISauce Sauce { get; protected set; }
? ? ? ? public ICheese Cheese { get; protected set; }
? ? ? ? public IClams Clams { get; protected set; }
? ? ? ? public abstract void Prepare();
? ? ? ? public void Bake()
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("Bake for 25 minutes");
? ? ? ? }
? ? ? ? public void Cut()
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("Cutting the pizza into diagnol slices");
? ? ? ? }
? ? ? ? public void Box()
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("Placing pizza in official PizzaStore box......");
? ? ? ? }
? ? }
}
具體原料:
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class FreshClams : IClams
? ? {
? ? ? ? public string Name { get; } = "Fresh Clams";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class FrozenClams: IClams
? ? {
? ? ? ? public string Name { get; } = "Frozen Clams";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class MarinaraSauce: ISauce
? ? {
? ? ? ? public string Name { get; } = "Marinara Sauce";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class MozzarellaCheese: ICheese
? ? {
? ? ? ? public string Name { get; } = "Mozzarella Cheese";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class PlumTomatoSauce : ISauce
? ? {
? ? ? ? public string Name { get; } = "Plum Tomato Sauce";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class ReggianoCheese : ICheese
? ? {
? ? ? ? public string Name { get; } = "Reggiano Cheese";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class ThickCrustDough: IDough
? ? {
? ? ? ? public string Name { get; } = "Thick Crust Dough";
? ? }
}
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.Ingredients
{
? ? public class ThinCrustDough: IDough
? ? {
? ? ? ? public string Name { get; } = "Thin Crust Dough";
? ? }
}
具體披薩:
using System;
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.ConcreteProducts
{
? ? public class CheesePizza: Pizza
? ? {
? ? ? ? private readonly IPizzaIngredientFactory _pizzaIngredientFactory;
? ? ? ? public CheesePizza(IPizzaIngredientFactory pizzaIngredientFactory)
? ? ? ? {
? ? ? ? ? ? _pizzaIngredientFactory = pizzaIngredientFactory;
? ? ? ? }
? ? ? ? public override void Prepare()
? ? ? ? {
? ? ? ? ? ? Console.WriteLine($"Preparing: {Name}");
? ? ? ? ? ? Dough = _pizzaIngredientFactory.CreateDough();
? ? ? ? ? ? Sauce = _pizzaIngredientFactory.CreateSauce();
? ? ? ? ? ? Clams = _pizzaIngredientFactory.CreateClams();
? ? ? ? ? ? Cheese = _pizzaIngredientFactory.CreateCheese();
? ? ? ? ? ? Console.WriteLine($"? ? {Dough.Name}");
? ? ? ? ? ? Console.WriteLine($"? ? {Sauce.Name}");
? ? ? ? ? ? Console.WriteLine($"? ? {Clams.Name}");
? ? ? ? ? ? Console.WriteLine($"? ? {Cheese.Name}");
? ? ? ? }
? ? }
}
using System;
using AbstractFactoryPattern.Abstractions;
namespace AbstractFactoryPattern.ConcreteProducts
{
? ? public class ClamsPizza : Pizza
? ? {
? ? ? ? private readonly IPizzaIngredientFactory _pizzaIngredientFactory;
? ? ? ? public ClamsPizza(IPizzaIngredientFactory pizzaIngredientFactory)
? ? ? ? {
? ? ? ? ? ? _pizzaIngredientFactory = pizzaIngredientFactory;
? ? ? ? }
? ? ? ? public override void Prepare()
? ? ? ? {
? ? ? ? ? ? Console.WriteLine($"Preparing: {Name}");
? ? ? ? ? ? Dough = _pizzaIngredientFactory.CreateDough();
? ? ? ? ? ? Sauce = _pizzaIngredientFactory.CreateSauce();
? ? ? ? ? ? Clams = _pizzaIngredientFactory.CreateClams();
? ? ? ? ? ? Console.WriteLine($"? ? {Dough.Name}");
? ? ? ? ? ? Console.WriteLine($"? ? {Sauce.Name}");
? ? ? ? ? ? Console.WriteLine($"? ? {Clams.Name}");
? ? ? ? }
? ? }
}
各地原料工廠:
using AbstractFactoryPattern.Abstractions;
using AbstractFactoryPattern.Ingredients;
namespace AbstractFactoryPattern.ConcreteFactories
{
? ? public class ChicagoPizzaIngredientFactory: IPizzaIngredientFactory
? ? {
? ? ? ? public IDough CreateDough()
? ? ? ? {
? ? ? ? ? ? return new ThinCrustDough();
? ? ? ? }
? ? ? ? public ICheese CreateCheese()
? ? ? ? {
? ? ? ? ? ? return new ReggianoCheese();
? ? ? ? }
? ? ? ? public IClams CreateClams()
? ? ? ? {
? ? ? ? ? ? return new FrozenClams();
? ? ? ? }
? ? ? ? public ISauce CreateSauce()
? ? ? ? {
? ? ? ? ? ? return new PlumTomatoSauce();
? ? ? ? }
? ? }
}
using AbstractFactoryPattern.Abstractions;
using AbstractFactoryPattern.Ingredients;
namespace AbstractFactoryPattern.ConcreteFactories
{
? ? public class NewYorkPizzaIngredientFactory: IPizzaIngredientFactory
? ? {
? ? ? ? public IDough CreateDough()
? ? ? ? {
? ? ? ? ? ? return new ThickCrustDough();
? ? ? ? }
? ? ? ? public ICheese CreateCheese()
? ? ? ? {
? ? ? ? ? ? return new MozzarellaCheese();
? ? ? ? }
? ? ? ? public IClams CreateClams()
? ? ? ? {
? ? ? ? ? ? return new FreshClams();
? ? ? ? }
? ? ? ? public ISauce CreateSauce()
? ? ? ? {
? ? ? ? ? ? return new MarinaraSauce();
? ? ? ? }
? ? }
}
各地披薩店:
using AbstractFactoryPattern.Abstractions;
using AbstractFactoryPattern.ConcreteFactories;
using AbstractFactoryPattern.ConcreteProducts;
namespace AbstractFactoryPattern.Clients
{
? ? public class ChicagoPizzaStore : PizzaStore
? ? {
? ? ? ? protected override Pizza CreatePizza(string type)
? ? ? ? {
? ? ? ? ? ? var factory = new ChicagoPizzaIngredientFactory();
? ? ? ? ? ? Pizza pizza = null;
? ? ? ? ? ? switch (type)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? case "cheese":
? ? ? ? ? ? ? ? ? ? pizza = new CheesePizza(factory);
? ? ? ? ? ? ? ? ? ? pizza.Name = "Chicago Cheese Pizza";
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case "clams":
? ? ? ? ? ? ? ? ? ? pizza = new ClamsPizza(factory);
? ? ? ? ? ? ? ? ? ? pizza.Name = "Chicago Clams Pizza";
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? return pizza;
? ? ? ? }
? ? }
}
using AbstractFactoryPattern.Abstractions;
using AbstractFactoryPattern.ConcreteFactories;
using AbstractFactoryPattern.ConcreteProducts;
namespace AbstractFactoryPattern.Clients
{
? ? public class NewYorkPizzaStore : PizzaStore
? ? {
? ? ? ? protected override Pizza CreatePizza(string type)
? ? ? ? {
? ? ? ? ? ? var factory = new NewYorkPizzaIngredientFactory();
? ? ? ? ? ? Pizza pizza = null;
? ? ? ? ? ? switch (type)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? case "cheese":
? ? ? ? ? ? ? ? ? ? pizza = new CheesePizza(factory);
? ? ? ? ? ? ? ? ? ? pizza.Name = "New York Cheese Pizza";
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case "clams":
? ? ? ? ? ? ? ? ? ? pizza = new ClamsPizza(factory);
? ? ? ? ? ? ? ? ? ? pizza.Name = "New York Clams Pizza";
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? return pizza;
? ? ? ? }
? ? }
}
測試運行:
using System;
using AbstractFactoryPattern.Clients;
namespace AbstractFactoryPattern
{
? ? class Program
? ? {
? ? ? ? static void Main(string[] args)
? ? ? ? {
? ? ? ? ? ? var newYorkPizzaStore = new NewYorkPizzaStore();
? ? ? ? ? ? newYorkPizzaStore.OrderPizza("cheese");
? ? ? ? ? ? Console.WriteLine("-----------------------------------------------------------");
? ? ? ? ? ? var chicagoYorkPizzaStore = new ChicagoPizzaStore();
? ? ? ? ? ? chicagoYorkPizzaStore.OrderPizza("cheese");
? ? ? ? ? ? Console.ReadKey();
? ? ? ? }
? ? }
}?
相關(guān)文章:
C# ?觀察者模式 以及 delegate 和 event
用C#(.NET Core) 實現(xiàn)簡單工廠和工廠方法設(shè)計模式
原文地址 http://www.cnblogs.com/cgzl/p/8776868.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的用C# (.NET Core) 实现抽象工厂设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软西雅图总部DevOps交流总结
- 下一篇: Project Honolulu 正式版