工廠模式
針對接口編程,可以隔離掉以后系統可能發生的一大堆改變。如果一個類中使用大量new出來的具體類,那么就等于是自找麻煩,因為一旦加入新的具體類,就必須修改代碼。
我們可以將new的工作,交給一個對象去做,這個對象被我們稱為“工廠”。
工廠(factory)處理創建對象的細節。把創建工作交給一個對象來處理的好處就是日后要修改時,只需要修改這個類即可。
我們很喜歡利用靜態方法定義一個工廠,通常稱為“靜態工廠”,這樣就不用使用創建對象的方法來實例化對象了,但這樣的靜態工廠有個缺點,就是不能通過繼承來改變創建方法的行為。
簡單工廠
其實,它不是一個設計模式,更像是一種編程習慣。下面的例子是關于簡單工廠的:
UML:
沒有使用工廠模前,FourSStore類的內-的:
public class FourSStore { public Vehicle orderVehicle(String type){ Vehicle vehicle; switch (type) { case "car.Benz": vehicle = new Benz(); break; case "car.BMW": vehicle = new BMW(); break; case "car.BYD": vehicle = new BYD(); break; case "car.Volkswagon": vehicle = new Volkswagon(); break; } if(factory != null){ vehicle = factory.createVehicle(type); System.out.println(vehicle.brand()+"\n"); System.out.println(vehicle.price()+"\n"); System.out.println(vehicle.oilWear()+"\n"); System.out.println(vehicle.outputVolumn()+"\n"); return vehicle; } 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
26
27
28
29
30
31
用了簡單工廠模式后是這樣的:
public class FourSStore { private SimpleVehicleFactory factory; public FourSStore(SimpleVehicleFactory factory){ this.factory = factory; } public Vehicle orderVehicle(String type){ Vehicle vehicle; if(factory != null){ vehicle = factory.createVehicle(type); System.out.println(vehicle.brand()+"\n"); System.out.println(vehicle.price()+"\n"); System.out.println(vehicle.oilWear()+"\n"); System.out.println(vehicle.outputVolumn()+"\n"); return vehicle; } return null; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
就是把實化對象的工作,交給了工廠類simpleVehicleFactory類來完成,日后修改也會少很多,增加新的對象只需要在工廠中修改即可。
public class SimpleVehicleFactory { public Vehicle createVehicle(String type) { switch (type) { case "car.Benz": return new Benz(); case "car.BMW": return new BMW(); case "car.BYD": return new BYD(); case "car.Volkswagon": return new Volkswagon(); } return null; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
簡單工廠模式的代碼已分享在GitHub上。
靜態工廠
創建對象的方法是靜態的,如:
public static Vehicle createVehicle(String type) { switch (type) { case "Benz": return new Benz(); case "BMW": return new BMW(); case "BYD": return new BYD(); case "Volkswagon": return new Volkswagon(); } return null; }
1
2
3
4
5
6
7
8
9
10
11
12
13
使用的時候就不用實例化工廠對象了,如:
Vehicle vehicle = StaticVehicleFactory.createVehicle(type);
1
2
靜態工廠缺點就是不能通過繼承來改變創建方法的行為。
靜態工廠的demo也已分享在GitHub上了,歡迎下載。
工廠方法模式
**定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個。工廠方法讓類把實化推遲到了子類。**如下有一個例子:
父類中有一個決定創建對象實例的抽象方法。
public abstract class FourSStore { public Vehicle orderVehicle(String type){ Vehicle vehicle = createVehicle(type); if(vehicle != null){ System.out.println(vehicle.brand()+"\n"); System.out.println(vehicle.price()+"\n"); System.out.println(vehicle.oilWear()+"\n"); System.out.println(vehicle.outputVolumn()+"\n"); return vehicle; } return null; } public abstract Vehicle createVehicle(String type); //決定創建對象實例的抽象方法,將由子類來實現 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
子類:
public class GuangZhou4sStore extends FourSStore { @Override public Vehicle createVehicle(String type) { switch (type) { case "Benz": return new Benz(); case "BMW": return new BMW(); case "BYD": return new BYD(); case "Volkswagon": return new Volkswagon(); } return null; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
測試:
public class Main { public static void main(String[] args) { FourSStore store = new GuangZhou4sStore(); store.orderVehicle("Volkswagon"); } }
1
2
3
4
5
6
7
8
9
10
測試結果
…
/home/wong/Desktop/FactoryMethodPattern/out/production/FactoryMethodPattern Main
Woldswagon
40000.0
1.3
12.0
Process finished with exit code 0
工廠方法模式與簡單工廠模式,相同點就是都是創建創建對象實例的工作交給一個類來完成,不同點是工廠方法是交給子類從父類繼承而來的抽象方法中來完成的,簡單工廠模式則是自建的工廠類。
工廠方法模式幫助我們將產品的“實現”從“使用”中解耦。
上面的實例,都通過傳參來決定要創建哪個產品,這叫做“參數化工廠方法”。如果是只生產一種對象(產品),那么可以不需要參數化。
抽象工廠模式
提供一個接口,用于創建相關或依賴對象的家族,而不需要明確指定具體類。
抽象工廠允許客戶使用抽象的接口來創建一組相關的產品,而不需要知道(或關心)實際產生的具體產品是什么。這樣客戶就可從具體的產品中解耦。
抽象工廠的每個方法實際上看起來都像是工廠方法。每個方法都被聲明成抽象,而子類的方法覆蓋這些方法來創建某些對象。
抽象工廠的任務是定義一個負責創建一組產品的接口。這個接口內的每個方法都負責創建一個具體產品,同時我們利用實現抽象工廠的子類來提供這些具體的做法。
利用工廠方法創建對象,需要擴展一個類,并覆蓋它的工廠方法。工廠方法是通過子類來創建對象。用這種做法,客戶只需要知道他們所使用的抽象類型就可以了,而由子類來負責決定具體類型。
抽象工廠的具體工廠經常實現工廠方法來創建他們的產品。
抽象工廠提供一個用來創建一個產品家族的抽象類型,這個類型的子類定義了產品產生的方法。要想使用這個工廠必須先實例化它,然后將它傳入一些針對抽象類型所寫的代碼中。
抽象工廠模式,如果要加入新產品就必須改變接口,即要修改抽象工廠中的抽象方法,子類也要提供實現,這個可能是抽象工廠模式的缺點之一。
工廠方法可以把客戶代碼從需要實例化的具體類中解耦。只要繼承含有工廠方法的抽象對象,并實現其工廠方法就可以了。
抽像工廠模式的demo代碼放在GitHub上了,歡迎下載學習。
其他
簡單工廠把全部事情,在一個地方都處理完了。然而工廠方法卻是創建了一個框架,讓子類來決定要如何實現。簡單工廠的做法,可以將對象的創建封裝起來,但是簡單工廠不具備工廠方法所擁有的彈性,因為簡單工廠不能變更正在創建的產品。
將創建對象的代碼集中在一個對象或方法中,可以避免代碼中的重復,并且更方便以后的維護。這也意味著客戶在實例化對象時,只會依賴于接口,而不是具體的類。
**當你直接實例化一個對象時,就是在依賴它的具體類。**在代碼里減少對于具體類的依賴是件“好事”。**要依賴抽象,不要依賴具體類,這叫依賴倒置原則。**依賴倒置原則必須有以下三個特點:
變量不可以持有具體類的引用。如果用new就會持有具體類的引用,解決方法可以通過工廠來避免。
不要讓類派生自具體類。可以派生自一個抽象(抽象類或接口)。
不要覆蓋基類中已實現的方法。覆蓋了基類已實現的方法,那么這個基類就不是一個真正適合被繼承的抽象。基類中已實現的方法,應該由所有子類所共享。
總結:
所有的工廠都是用來封裝對象的創建。
簡單工廠,雖然不是真正的設計模式,卻不失為一個簡單的方法,可以將客戶程序從具體類解耦。
工廠方法使用繼承:把對象的創建委托給子類,子類實現工廠方法來創建對象
抽象工廠使用對象組合:對象的創建被實現在工廠接口所暴露出來的方法中。
所有工廠模式都通過減少應用程序和具體類之間的依賴促進松耦合。
工廠方法允許將實例化延遲到子類進行。
抽象工廠創建相關的對象家族,而不需要依賴它們的具體類。
依賴倒置原則,指導我們避免依賴具體類型,而要盡量依賴抽象。
工廠幫助我們針對抽象編程,而不是針對具體類編程。
謝謝閱讀!
GitHub
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。