日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

用C#(.NET Core) 实现简单工厂和工厂方法设计模式

發布時間:2023/12/4 C# 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用C#(.NET Core) 实现简单工厂和工厂方法设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文源自深入淺出設計模式. 只不過我是使用C#/.NET Core實現的例子.

?

前言

當你看見new這個關鍵字的時候, 就應該想到它是具體的實現.

這就是一個具體的類, 為了更靈活, 我們應該使用的是接口(interface).

有時候, 你可能會寫出這樣的代碼:

這里有多個具體的類被實例化了, 是根據不同情況在運行時被實例化的.?

當你看到這樣的代碼, 你就會知道當有需求需要對其進行修改或者擴展的時候, 你就得把這個文件打開, 然后看看在這里應該添加或者刪除點什么. 這類的代碼經常會分散在程序的多個地方, 這維護和更新起來就很麻煩而且容易出錯.

針對interface進行編程的時候, 你知道可以把自己獨立于系統未來可能要發生的變化. 為什么呢? 因為如果你針對interface編程, 那么對于任何實現了該接口的具體類對你來說都可以用, 多態嗎.

項目原始需求

有一個前沿的披薩店, 做披薩, 下面是訂購披薩的類:

new一個披薩, 然后按照工序進行加工 最后返回披薩.

但是, 一個披薩店不可能只有一種披薩, 可能會有很多中披薩, 所以你可能會這樣修改代碼:

根據傳入的類型, 創建不同的披薩, 然后加工返回.

然后問題來了, 隨著時間的推移, 一個披薩店會淘汰不暢銷的披薩并添加新品種披薩.

使用上面的代碼就會出現這個問題, 針對需求變化, 我不得不把OrderPizza的部分代碼改來改去:

從這里, 我們也可以看到, 上半部分是會變化的部分, 下半部分是不變的部分, 所以它們應該分開(把變化的部分和不變的部分分開, 然后進行封裝).

結構應該是這樣的:

右上角是變化的部分, 把這部分封裝到一個對象里, 它就是用來創建披薩的對象, 我們把這個對象叫做:?工廠.

工廠負責創建對象的細節工作. 我們創建的這個工廠叫做SimplePizzaFactory, 而orderPizza()這個方法就是該工廠的一個客戶(client).

任何時候客戶需要披薩的時候, 披薩工廠就會給客戶創建一個披薩.

接下來, 我們就建立這個簡易的披薩工廠:

就是通過傳入的類型參數, 建立并返回不同類型的披薩.

這樣我們就把披薩創建的工作封裝到了一個類里面, 發生變化的時候, 只需要修改這一個類即可.

注意: 有時候上面這種簡單工廠可以使用靜態方法, 但是這樣也有缺點, 就是無法通過繼承來擴展這個工廠了.

回來修改PizzaStore這個類:

工廠是從構造函數傳入的, 并在PizzaStore里面保留一個引用.

在OrderPizza()方法里面, 我們使用工廠的創建方法代替了new關鍵字, 所以在這里沒有具體的實例化.

簡單工廠的定義

簡單/簡易工廠并不是一個設計模式, 更多是一個編程習慣. 但是使用的非常廣泛.

簡單工廠類圖:

這個很簡單, 就不解釋了.?

簡單工廠就到這, 下面要講兩個重量級的工廠模式.

用C#/.NET Core實現簡單工廠

Pizza父類:

using System;

using System.Collections.Generic;


namespace SimpleFactory.Pizzas

{

? ? public abstract class Pizza

? ? {

? ? ? ? public string Name { get; protected set; }

? ? ? ? public string Dough { get; protected set; }

? ? ? ? public string Sauce { get; protected set; }

? ? ? ? protected List<string> Toppings = new List<string>();


? ? ? ? public void Prepare()

? ? ? ? {

? ? ? ? ? ? Console.WriteLine($"Preparing: {Name}");

? ? ? ? ? ? Console.WriteLine($"Tossing: {Dough}");

? ? ? ? ? ? Console.WriteLine($"Adding sauce: {Sauce}");

? ? ? ? ? ? Console.WriteLine("Adding toppings: ");

? ? ? ? ? ? Toppings.ForEach(x => Console.WriteLine($"? {x}"));

? ? ? ? }


? ? ? ? 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......");

? ? ? ? }

? ? }

}

各種Pizza:

namespace SimpleFactory.Pizzas

{

? ? public class CheesePizza: Pizza

? ? {

? ? ? ? public CheesePizza()

? ? ? ? {

? ? ? ? ? ? Name = "Cheese Pizza";

? ? ? ? ? ? Dough = "Think Dough";

? ? ? ? ? ? Sauce = "Salad";

? ? ? ? ? ? Toppings.Add("Grated Reggiano Cheese");

? ? ? ? }

? ? }

}


namespace SimpleFactory.Pizzas

{

? ? public class ClamPizza: Pizza

? ? {

? ? ? ? public ClamPizza()

? ? ? ? {

? ? ? ? ? ? Name = "Clam Pizza";

? ? ? ? ? ? Sauce = "Tomato sauce";

? ? ? ? ? ? Dough = "Soft dough";

? ? ? ? ? ? Toppings.Add("Shrimp meat");

? ? ? ? }

? ? }

}


namespace SimpleFactory.Pizzas

{

? ? public class PepperoniPizza: Pizza

? ? {

? ? ? ? public PepperoniPizza()

? ? ? ? {

? ? ? ? ? ? Name = "Pepperoni Pizza";

? ? ? ? ? ? Dough = "Thin dough";

? ? ? ? ? ? Sauce = "Black pepper";

? ? ? ? ? ? Toppings.Add("Beef Granules");

? ? ? ? ? ? Toppings.Add("Niblet");

? ? ? ? }

? ? }

}

簡單工廠:

using SimpleFactory.Pizzas;


namespace SimpleFactory

{

? ? public class SimplePizzaFactory

? ? {

? ? ? ? public Pizza CreatePizza(string type)

? ? ? ? {

? ? ? ? ? ? Pizza pizza = null;

? ? ? ? ? ? switch (type)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? case "cheese":

? ? ? ? ? ? ? ? ? ? pizza = new CheesePizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case "pepperoni":

? ? ? ? ? ? ? ? ? ? pizza = new PepperoniPizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case "clam":

? ? ? ? ? ? ? ? ? ? pizza = new ClamPizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }


? ? ? ? ? ? return pizza;

? ? ? ? }

? ? }

}


PizzaStore:

using SimpleFactory.Pizzas;


namespace SimpleFactory

{

? ? public class PizzaStore

? ? {

? ? ? ? private readonly SimplePizzaFactory _factory;


? ? ? ? public PizzaStore(SimplePizzaFactory factory)

? ? ? ? {

? ? ? ? ? ? _factory = factory;

? ? ? ? }


? ? ? ? public Pizza OrderPizza(string type)

? ? ? ? {

? ? ? ? ? ? var pizza = _factory.CreatePizza(type);

? ? ? ? ? ? pizza.Prepare();

? ? ? ? ? ? pizza.Bake();

? ? ? ? ? ? pizza.Cut();

? ? ? ? ? ? pizza.Box();

? ? ? ? ? ? return pizza;

? ? ? ? }

? ? }

}

測試運行:

using System;


namespace SimpleFactory

{

? ? class Program

? ? {

? ? ? ? static void Main(string[] args)

? ? ? ? {

? ? ? ? ? ? var pizzaStore = new PizzaStore(new SimplePizzaFactory());

? ? ? ? ? ? var cheesePizza = pizzaStore.OrderPizza("cheese");

? ? ? ? ? ? Console.WriteLine();

? ? ? ? ? ? var clamPizza = pizzaStore.OrderPizza("pepperoni");

? ? ? ? ? ? Console.ReadKey();

? ? ? ? }

? ? }

}

?

需求變更 - 授權連鎖披薩店

?披薩店開的很好, 所以老板在全國各地開授權連鎖分店了, 而每個地點的分店根據當地居民的口味, 它們所提供的披薩種類可能會不同.

例如紐約和芝加哥和加利福尼亞的就有可能不同.

針對這個需求, 我們可能會想到的第一種辦法就是: 把SimplePizzaFactory抽取出來, 分別建立三個地點的工廠, 然后根據地點把相應的工廠組合到PizzaStore

代碼是這樣的:

紐約:

芝加哥:

因為個連鎖店分布在各地, 老板想做質量管控: 做披薩的基本工序應該是一樣的, 但是針對某種披薩各地可以有不同的風格做法.

所以我們把createPizza()方法放回到PizzaStore, 但這次它是抽象方法, 然后各地都會創建自己的PIzzaStore:

下面是紐約和芝加哥的披薩店:

針對每種披薩, 紐約和芝加哥可能會有自己風格具體實現的披薩.

orderPizza()方法是在父類/抽象類里面實現的, 這里的披薩還是抽象的, 所以它并不知道是PizzaStore的哪個子類來做的披薩.

代碼運行的時候, orderPizza()會調用createPizza()方法, PizzaStore的某個子類肯定會對此負責.

所以你哪個地方的PizzaStore, 就會決定產出的是哪個地方特產的披薩.

?

下面就創建PizzaStore, 例如紐約的:

其他地點的都差不多, 就不貼圖了.

如何聲明一個工廠方法

還是看這張圖:

抽象的PizzaStore把訂購披薩的固定工序orderPizza()放在了抽象類里面.

創建披薩createPizza()方法是在各地的披薩店里做實現.

用一行代碼來解釋工廠方法就是:

工廠方法是讓其子類具體來實現對象創建的工作. 這樣就把父類中的客戶代碼和子類的創建對象部分的代碼解耦了.

?

上面工作做的挺好, 但是還差一件事....披薩.

首先抽象父類:

里面定義了調味料和工序

然后具體的披薩:

紐約的奶酪披薩

芝加哥的奶酪披薩

最后運行一下:

?

工廠方法模式

所有的工廠模式都會封裝對象的創建過程, 而工廠方法模式把對象創建的動作交給了子類, 并讓它決定創建哪些對象.

創建者:

?

產品:

看看另外一種結構 -- 并行的類結構:

?

工廠方法模式的定義:

工廠方法模式定義了一個創建對象的接口, 但是讓子類來決定具體創建的是哪一個對象. 工廠方法讓一個類延遲實例化, 直到子類的出現.

左邊是產品, 所有具體的產品都應該繼承于同一個父類/接口.

右邊的Creator類里面包含所有方法的實現除了抽象的工廠方法. 這個抽象的工廠方法在Creator的子類里面必須進行實現, 產品就是在子類具體實現的工廠方法里面創造出來的.

?

設計原則 -- 應該依賴于抽象, 而不依賴于具體的類

這就是著名的:?DIP (Dependency Inversion Principle) 依賴反轉原則.

進一步解釋就是:?高級別的組件不應該依賴于低級別的組件, 它們都應該依賴于抽線.

高級別組件, 就是它有一組行為定義在另外一堆低級別的組件里面了.

例如PizzaStore就是高級別的, 具體的披薩就是低級別的.

應該該設計原則后:

這時它們都依賴于抽象的披薩父類了.

實現該原則的三點指導建議

  • 沒有變量引用具體的類(可已使用工廠代替創建這個具體的類)

  • 沒有類派生于具體的類(派生于它就依賴于它)

  • 不去重寫(override)其任一父類的已實現方法(如果重寫了, 那么這個類并不適合作為起始的抽象類, 因為基類里面的方法本應該是共享與所有子類的)

和其它原則一樣, 只是盡力去按照這三點建議去執行, 并不是必須一直要這么做.

C#/.NET Core的代碼實現

各種pizza:

namespace FactoryMethodPattern.Pizzas

{

? ? public class ChicagoCheesePizza : Pizza

? ? {

? ? ? ? public ChicagoCheesePizza()

? ? ? ? {

? ? ? ? ? ? Name = "Chicago Cheese Pizza";

? ? ? ? ? ? Dough = "Think Dough 1";

? ? ? ? ? ? Sauce = "Salad 1";

? ? ? ? ? ? Toppings.Add("Grated Reggiano Cheese 1");

? ? ? ? }

? ? }

}


namespace FactoryMethodPattern.Pizzas

{

? ? public class ChicagoClamPizza : Pizza

? ? {

? ? ? ? public ChicagoClamPizza()

? ? ? ? {

? ? ? ? ? ? Name = "Chicago Clam Pizza";

? ? ? ? ? ? Sauce = "Tomato sauce 1";

? ? ? ? ? ? Dough = "Soft dough 1";

? ? ? ? ? ? Toppings.Add("Shrimp meat 1");

? ? ? ? }

? ? }

}


namespace FactoryMethodPattern.Pizzas

{

? ? public class ChicagoPepperoniPizza : Pizza

? ? {

? ? ? ? public ChicagoPepperoniPizza()

? ? ? ? {

? ? ? ? ? ? Name = "Chicago Pepperoni Pizza";

? ? ? ? ? ? Dough = "Thin dough 1";

? ? ? ? ? ? Sauce = "Black pepper 1";

? ? ? ? ? ? Toppings.Add("Beef Granules 1");

? ? ? ? ? ? Toppings.Add("Niblet 1");

? ? ? ? }

? ? }

}


namespace FactoryMethodPattern.Pizzas

{

? ? public class NYCheesePizza: Pizza

? ? {

? ? ? ? public NYCheesePizza()

? ? ? ? {

? ? ? ? ? ? Name = "NY Cheese Pizza";

? ? ? ? ? ? Dough = "Think Dough 2";

? ? ? ? ? ? Sauce = "Salad 2";

? ? ? ? ? ? Toppings.Add("Grated Reggiano Cheese 2");

? ? ? ? }

? ? }

}


namespace FactoryMethodPattern.Pizzas

{

? ? public class NYClamPizza: Pizza

? ? {

? ? ? ? public NYClamPizza()

? ? ? ? {

? ? ? ? ? ? Name = "NY? Clam Pizza";

? ? ? ? ? ? Sauce = "Tomato sauce 2";

? ? ? ? ? ? Dough = "Soft dough 2";

? ? ? ? ? ? Toppings.Add("Shrimp meat 2");

? ? ? ? }

? ? }

}


namespace FactoryMethodPattern.Pizzas

{

? ? public class NYPepperoniPizza: Pizza

? ? {

? ? ? ? public NYPepperoniPizza()

? ? ? ? {

? ? ? ? ? ? Name = "NY Pepperoni Pizza";

? ? ? ? ? ? Dough = "Thin dough 2";

? ? ? ? ? ? Sauce = "Black pepper 2";

? ? ? ? ? ? Toppings.Add("Beef Granules 2");

? ? ? ? ? ? Toppings.Add("Niblet 2");

? ? ? ? }

? ? }

}

披薩店抽象父類:

using FactoryMethodPattern.Pizzas;


namespace FactoryMethodPattern

{

? ? 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);

? ? }

}

Chicago披薩店:

using FactoryMethodPattern.Pizzas;


namespace FactoryMethodPattern

{

? ? public class ChicagoPizzaStore: PizzaStore

? ? {

? ? ? ? protected override Pizza CreatePizza(string type)

? ? ? ? {

? ? ? ? ? ? Pizza pizza = null;

? ? ? ? ? ? switch (type)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? case "cheese":

? ? ? ? ? ? ? ? ? ? pizza = new ChicagoCheesePizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case "pepperoni":

? ? ? ? ? ? ? ? ? ? pizza = new ChicagoPepperoniPizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case "clam":

? ? ? ? ? ? ? ? ? ? pizza = new ChicagoClamPizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }


? ? ? ? ? ? return pizza;

? ? ? ? }

? ? }

}

紐約披薩店:

using FactoryMethodPattern.Pizzas;


namespace FactoryMethodPattern

{

? ? public class NYPizzaStore : PizzaStore

? ? {

? ? ? ? protected override Pizza CreatePizza(string type)

? ? ? ? {

? ? ? ? ? ? Pizza pizza = null;

? ? ? ? ? ? switch (type)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? case "cheese":

? ? ? ? ? ? ? ? ? ? pizza = new NYCheesePizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case "pepperoni":

? ? ? ? ? ? ? ? ? ? pizza = new NYPepperoniPizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? case "clam":

? ? ? ? ? ? ? ? ? ? pizza = new NYClamPizza();

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? }


? ? ? ? ? ? return pizza;

? ? ? ? }

? ? }

}


測試運行:

using System;


namespace FactoryMethodPattern

{

? ? class Program

? ? {

? ? ? ? static void Main(string[] args)

? ? ? ? {

? ? ? ? ? ? var nyStore = new NYPizzaStore();

? ? ? ? ? ? var chicagoStore = new ChicagoPizzaStore();


? ? ? ? ? ? var pizza = nyStore.OrderPizza("cheese");

? ? ? ? ? ? Console.WriteLine($"Ordered a {pizza.Name} in NY");

? ? ? ? ? ? Console.WriteLine();

? ? ? ? ? ? var pizza2 = chicagoStore.OrderPizza("cheese");

? ? ? ? ? ? Console.WriteLine($"Ordered a {pizza2.Name} in Chicago");


? ? ? ? ? ? Console.ReadKey();

? ? ? ? }

? ? }

}


?

相關文章:

  • C# ?觀察者模式 以及 delegate 和 event

原文地址 http://www.cnblogs.com/cgzl/p/8760250.html


.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

總結

以上是生活随笔為你收集整理的用C#(.NET Core) 实现简单工厂和工厂方法设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。