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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

《Head First设计模式》第四章笔记 工厂模式

發(fā)布時間:2023/12/13 asp.net 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《Head First设计模式》第四章笔记 工厂模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

之前我們一直在使用new操作符,但是實例化這種行為并不應該總是公開的進行,而且初始化經(jīng)常會造成耦合問題,工廠模式將擺脫這種復雜的依賴,本次內(nèi)容包括簡單工廠,工廠方法和抽象工廠三種情況。

1

2

3

4

5

6

Duck duck;

if(a){

????duck=new Duck1();

}else{

????duck=new Duck2();

}

如上面代碼中使用new實例化一個類時,使用的是實現(xiàn),而不是接口,代碼捆綁著具體類會導致代碼更脆弱缺乏彈性,后續(xù)的維護、修改等操作容易出錯。

使用new操作符會造成的問題:

1.如果你針對接口編程,你可以利用多態(tài),實現(xiàn)該接口并沒有太大問題
2.但是如果代碼中使用了很多具體類,一旦加入新的類,就必須改變代碼,這就違反了開放-關(guān)閉原則。

項目舉例

假設你有一家 pizza 店,你有很多種 pizza,要在系統(tǒng)中顯示你所有pizza種類。
實現(xiàn)這個功能并不難,

使用普通方式實現(xiàn):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public class PizzaStore {

????Pizza orderPizza(String type) {

????????Pizza pizza =?null;

????????if (type.equals("cheese")) {

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

????????}?else if (type.equals("clam")) {

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

????????}?else if (type.equals("veggie")) {

????????????pizza =?new VeggiePizza();

????????}

????????pizza.prepare();

????????pizza.bake();

????????pizza.cut();

????????pizza.box();

????????return pizza;

????}

}

但是如果新上市一種pizza或者下架一種pizza,你就需要修改這段代碼,這樣就沒有做到對修改關(guān)閉。

簡單工廠:

于是我們使用之前學到的知識,找到變化的代碼和不變的代碼,進行封裝了:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

public class SimpleFactory {

????public Pizza createPizza(String type) {

????????Pizza pizza =?null;

????????if (type.equals("cheese")) {

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

????????}?else if (type.equals("clam")) {

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

????????}?else if (type.equals("veggie")) {

????????????pizza =?new VeggiePizza();

????????}

????????return pizza;

????}

}

?

public class PizzaStore {

????SimpleFactory simpleFactory;

????public PizzaStore(SimpleFactory simpleFactory) {

????????this.simpleFactory = simpleFactory;

????}

????Pizza orderPizza(String type) {

????????Pizza pizza =?null;

????????pizza = simpleFactory.createPizza(type);

????????pizza.prepare();

????????pizza.bake();

????????pizza.cut();

????????pizza.box();

????????return pizza;

????}

}

這么做的好處看起來好像只是把原來的代碼放進到另外一個類中,但是當以后出現(xiàn)變化時,自需要修改這個類,就可以,并且這樣做的好處還在于可能現(xiàn)在只有客人點餐才會用到這段代碼,如果可以點外賣的話,仍然可以用這段代碼,代碼得到了復用


上面的簡單工廠并不是一個真正的模式,只是一種編程習慣,這個不能算工廠模式,不過也算是基本滿足需求。

工廠方法模式:

背景更新:假如現(xiàn)在你要開分店,各種加盟商進來后,他們都要開發(fā)符合本地口味的pizza,那就需要各個地方都有一個工廠,也就是每個地方繼承SimpleFactory類,但是每個工廠并不是完全使用你原來的烘培方法。

工廠方法模式類圖如下:

對應代碼·:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

public abstract class PizzaStore {

????Pizza orderPizza(String type) {

????????Pizza pizza =?null;

????????pizza = createPizza(type);

????????pizza.prepare();

????????pizza.bake();

????????pizza.cut();

????????pizza.box();

????????return pizza;

????}

????protected abstract Pizza createPizza(String type);

}

?

public class NYPizzaStore?extends PizzaStore {

????@Override

????protected Pizza createPizza(String type) {

????????if (type.equals("cheese")) {

????????????return new NYCheesePizza();

????????}

????return null;

????}

}

?

public class ChicagoPizzaStore?extends PizzaStore {

????@Override

????protected Pizza createPizza(String type) {

????????if (type.equals("cheese")) {

????????????return new ChicagoCheesePizza();

????????}

????return null;

????}

}

現(xiàn)在訂購這些訂單時,自需要實例化各自風格的工廠,就算都是芝士披薩,也是來自不同商店口味的。

?

?

總結(jié):

  • 工廠方法模式定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的是哪一個,工廠方法讓類把實例化推遲到子類,工廠方法模式的優(yōu)點在于幫助產(chǎn)品從使用中分離,從使用中解耦。
  • 和簡單工廠的區(qū)別,兩者類似,但是在于createPizza方法,工廠方法讓每個上篇自行負責,而簡單工廠使用的則是PizzaStore對象。
  • 簡單工廠把所有的事情在一個地方干完了,然而工廠方法則是寫了一個框架,讓子類具體實現(xiàn),PizzaStore作為工廠的orderPizza方法提供了一個一般的框架,以便創(chuàng)建披薩,其具體依賴工廠的方法來創(chuàng)建具體的披薩。
  • 兩者都實現(xiàn)了不讓創(chuàng)建對象的代碼到處亂跑。

看看對象依賴情況,原來的PizzaStore依賴于所有的Pizza對象,當這些對象發(fā)生改變時,可能會影響到PizzaStore,PizzaStore時依賴具體類的,PizzaStore就是高層組件,Pizza各種對象就是低層組件,但是設計原則有一條是:依賴抽象,不要依賴具體類
而使用工廠方法之后就不在出現(xiàn)這種依賴很多具體類的情況了。

?

現(xiàn)在背景有變,有些加盟店,使用低價原料來增加利潤,你必須采取一些手段,以免毀掉你的披薩店品牌。
你打算建造一家成產(chǎn)原料的工廠,并將原料運送到各家加盟店,那么剩下最后一個問題,不同的區(qū)域原料是不一樣的,對于兩個加盟店給出了兩組不同的原料。

?

類圖:

?

建造原料工廠
我們要建造一個工廠來生產(chǎn)原料,這個工廠負責創(chuàng)建原料家族中的每一種原料。

1

2

3

4

5

6

7

8

public interface PizzaIngredientFactory {

????public Dough createDough();

????public Sauce createSauce();

????public Cheese createCheese();

????public Veggies[] createVeggies();

????public Pepperoni createPepperoni();

????public Clams createClams();

}

要做的事情是:
1.為每個區(qū)域建造一個工廠,你需要創(chuàng)建一個繼承自PizzaIngredientFactory的子類來實現(xiàn)每一個創(chuàng)建方法。
2.實現(xiàn)一組原料類供工廠使用,例如RegianoCheese,RedPeppers,ThickCrustDough.這些類可以在何時的區(qū)域間共享。
3.然后你仍然需要將這一切組織起來,將新的原料工廠整合進舊的PizzaStore代碼中。

創(chuàng)建紐約的原料工廠

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

class NYPizzaIngredientFactory?implements PizzaIngredientFactory{

????@Override

????public Dough createDough() {

??? ? ??return null;

????}

????@Override

????public Sauce createSauce() {

??? ? ??return null;

????}

????@Override

????public Cheese createCheese() {

??? ? ??return null;

????}

????@Override

????public Veggies[] createVeggies() {

??? ? ??return new Veggies[0];

????}

????@Override

????public Pepperoni createPepperoni() {

??? ? ??return null;

????}

????@Override

????public Clams createClams() {

??? ? ??return null;

????}

}

重做披薩

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

abstract class Pizza{

????String name;

????Dough dough;

????Sauce sauce;

????Veggies veggies[];

????Cheese cheese;

????Pepperoni pepperoni;

????Clams clams;

????abstract void prepare();

????void cut(){

??? ? ??System.out.println("Cutting the pizza into diagonal slices");

????}

????void box(){

??? ? ??System.out.println("Place pizza in official PizzaStore box");

????}

????void setName(String name){

??? ? ??this.name=name;

????}

????public String getName(){

??? ? ??return name;

????}

????public void toString2(){

??? ? ??//這里打印披薩的代碼

????}

}

繼續(xù)重做披薩

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class CheesePizza?extends Pizza {

????//這里組合了一個PizzaIngredientFactory對象的引用,用于提供不同的原料

????PizzaIngredientFactory ingredientFactory;

??

????/**

??? ?* 通過傳入一個PizzaIngredientFactory原料工廠,我們可以在制作Pizza的時候動態(tài)的產(chǎn)生所需要的原料

??? ?* @param ingredientFactory

??? ?*/

?????

????public CheesePizza(PizzaIngredientFactory ingredientFactory) {

??? ? ??this.ingredientFactory = ingredientFactory;

????}

??

????void prepare() {

??? ? ??System.out.println("Preparing " + name);

??? ? ??dough = ingredientFactory.createDough();

??? ? ??sauce = ingredientFactory.createSauce();

??? ? ??cheese = ingredientFactory.createCheese();

????}

}

再回到披薩店

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

public class NYPizzaStore?extends PizzaStore {

??

????protected Pizza createPizza(String item) {

??? ? ??Pizza pizza =?null;

??? ? ??PizzaIngredientFactory ingredientFactory =?new NYPizzaIngredientFactory();

??

??? ? ??if (item.equals("cheese")) {

???

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

??? ? ? ? ??pizza.setName("New York Style Cheese Pizza");

???

??? ? ??}?else if (item.equals("veggie")) {

??

??? ? ? ? ??pizza =?new VeggiePizza(ingredientFactory);

??? ? ? ? ??pizza.setName("New York Style Veggie Pizza");

??

??? ? ??}?else if (item.equals("clam")) {

??

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

??? ? ? ? ??pizza.setName("New York Style Clam Pizza");

??

??? ? ??}?else if (item.equals("pepperoni")) {

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

??? ? ? ? ??pizza.setName("New York Style Pepperoni Pizza");

??

??? ? ??}?

??? ? ??return pizza;

????}

}

我們做了些什么?
我們引入新類型的工廠,也就是所謂的抽象工廠,來創(chuàng)建披薩原料家族。
通過抽象工廠所提供的接口可以創(chuàng)建產(chǎn)品的家族,利用這個接口書寫代碼,我們的代碼將從實際工廠解耦,以便在不同上下文中實現(xiàn)各式各樣的工廠,制造出各種不同的產(chǎn)品。

定義抽象工廠模式

抽象工廠模式提供一個接口,用于創(chuàng)建相關(guān)或依賴對象的家族,而不需要明確指定具體類。

?

工廠方法與抽象工廠

抽象工廠的每個方法都實際上看起來像工廠方法,方法聲明成抽象,子類方法去覆蓋這些方法去創(chuàng)建對象。
抽象工廠的任務是定義一個負責創(chuàng)造一組產(chǎn)品的接口,每個方法就是創(chuàng)建一種產(chǎn)品,這就是工廠方法,所以在抽象工廠中利用工廠方法來實現(xiàn)生產(chǎn)方法是自然的。

對比:

  • 兩者都是用來創(chuàng)建對象,但是工廠方法使用的是繼承,而抽象工廠使用的是對象的組合。
  • 比如工廠方法創(chuàng)建pizza是各種PizzaStore繼承后覆蓋createPizza()方法實現(xiàn)的,讓客戶從具體類型中解耦。
  • 但是對于抽象工廠,提供了一個用來創(chuàng)建一個產(chǎn)品家族的抽象類型,這個類型的子類定義了產(chǎn)品被產(chǎn)生的方法,要想使用這個工廠必須實例化它,然后將它傳入一些針對抽象類型所寫的代碼中。
  • 比如PizzaIngredientFactory這個接口定義了一堆原料的做法,而對于紐約的原料加工廠先實現(xiàn)這些接口,然后紐約的商店實例化這個原料加工廠,就保證了不同的商店使用到各自不同的原料,把客戶從所使用的實際產(chǎn)品中解耦。
  • 一群還是一個,一群產(chǎn)品集合用抽象工廠,具體哪些類中可以確定一個抽象類,子類繼承實現(xiàn)使用工廠方法

?

?

設計原則:依賴倒置

依賴倒置原則:要依賴抽象,不要依賴具體類。高層次的模塊不應該依賴于低層次的模塊,他們都應該依賴于抽象。抽象不應該依賴于具體實現(xiàn),具體實現(xiàn)應該依賴于抽象。

用依賴倒置原則重構(gòu)代碼

下面是一些指導方針來避免違反依賴倒置原則:

  • 變量不可以持有具體類的引用。如果使用new,就會持有具體類的引用,你可以改成工廠來避免
  • 不要讓類派生自具體類,如果派生自具體類,你就會依賴具體類,請派生自抽象(接口或者抽象類)
  • 不要覆蓋基類中已經(jīng)實現(xiàn)的方法,如果覆蓋,那么基類說明就不是一個真正適合被繼承的抽象,基類中已經(jīng)實現(xiàn)的方法,應該有所有的子類共享

要盡量達到這些原則,但不是隨時都要遵守

?

總結(jié)

工廠:封裝對象的創(chuàng)建,處理創(chuàng)建對象的細節(jié)

靜態(tài)工廠:利用靜態(tài)方法定義一個簡單的工廠。優(yōu)點:不需要創(chuàng)建工廠類的實例化。缺點:不能通過繼承改變創(chuàng)建方法行為。

簡單工廠:簡單工廠并不是一種設計模式,因為只是簡單的把創(chuàng)建對象的代碼封裝起來

工廠模式:在父類定義了一個創(chuàng)建對象的接口,通過讓子類決定創(chuàng)建的對象是什么,來達到讓對象創(chuàng)建的過程封裝的目的。工廠方法讓類把實例化推遲到子類

抽象工廠:提供一個接口,用于創(chuàng)建相關(guān)或依賴對象的家族,而不需要指明具體的類

  • 工廠方法用來處理對象的創(chuàng)建,并將這樣的行為封裝在子類中。這樣客戶程序中超類的代碼就和子類對象的創(chuàng)建部分解耦了
  • 簡單工廠vs工廠模式:簡單工廠把全部的事情在一個地方做完了,而工廠模式是一個創(chuàng)建框架,讓子類決定如何實現(xiàn)
  • 抽象工廠vs工廠模式
    • 抽象工廠的方法經(jīng)常以工廠方法的方式實現(xiàn),抽象工廠的任務是定義一個負責創(chuàng)建一組產(chǎn)品的接口
    • 工廠方法使用繼承,抽象工廠使用組合
    • 工廠方法只是用來創(chuàng)建一種產(chǎn)品,而抽象工廠創(chuàng)建的是一個產(chǎn)品家族
    • 使用工廠模式意味著需要擴展一個類并覆蓋它的工廠方法。抽象工廠提供了一個創(chuàng)建產(chǎn)品家族的抽象類型,類型的子類定義了產(chǎn)品生產(chǎn)的方式

總結(jié)

以上是生活随笔為你收集整理的《Head First设计模式》第四章笔记 工厂模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。