java23種設計模式——三、工廠模式
目錄
java23種設計模式—— 一、設計模式介紹
java23種設計模式—— 二、單例模式
java23種設計模式——三、工廠模式
工廠模式
工廠模式介紹
工廠模式是我們最常用的實例化對象模式了,是用工廠方法代替new操作的一種模式。著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程序系統可以說是隨處可見。因為工廠模式就相當於創建實例對象的new,我們經常要根據類Class生成實例對象,如A a=new A() 工廠模式也是用來創建實例對象的,所以以後new時就要多個心眼,是否可以考慮使用工廠模式,雖然這樣做,可能多做一些工作,但會給你系統帶來更大的可擴展性和盡量少的修改量。(百度百科)
工廠模式又分為:
- 簡單工廠模式:允許接口創建對象,但不會暴露對象的創建邏輯。
- 工廠方法模式: 允許接口創建對象,但使用哪個類來創建對象,則是交由子類決定的
- 抽象方法模式: 抽象工廠是一個能夠創建一系列相關的對象而無需指定/公開其具體類的接口。該模式能夠提供其他工廠的對象,在其內部創建其他對象。
簡單工廠模式
屬於創建型模式,又叫做靜態工廠方法模式,不屬於23種GOF設計模式之一。是由一個工廠對象決定創建出哪一種產品類的實例。違背「開放 – 關閉原則」,一旦添加新產品就不得不修改工廠類的邏輯,這樣就會造成工廠邏輯過於複雜。
假設現在有一家餐館
public interface Restaurant {
public void cook();
}
餐館有兩種菜品:紅燒肉和雞蛋羹
//雞蛋羹
public class Egg implements Restaurant {
@Override
public void cook() {
System.out.println("雞蛋羹做好了");
}
}
//紅燒肉
public class Meet implements Restaurant{
@Override
public void cook() {
System.out.println("紅燒肉做好了");
}
}
餐館裏有服務員,來負責向後廚傳達客人的需求
public class Waiter {
//同樣可以定義常量然後通過switch語句來實現
public static Restaurant getFood(String orderType) {
Restaurant restaurant = null;
if(orderType.equals("紅燒肉")){
restaurant = new Meet();
}else if (orderType.equals("雞蛋羹")){
restaurant = new Egg();
}
return restaurant;
}
}
現在顧客來了,要點一份紅燒肉,就只需要和服務員說就行
public class Customer {
public static void main(String[] args) {
Restaurant restaurant = Waiter.getFood("紅燒肉");
restaurant.cook();
}
}
輸出
紅燒肉做好了
通過以上方法,的確實現了 提供創建實例的功能,而無需關心具體實現。但是我們不難發現,這種方法的擴展性很差,如果餐館新出了一款菜品,還需要我們在服務員方法里修改。這使得當餐館的菜品很多時,工廠方法代碼邏輯將會非常複雜
工廠方法模式
工廠方法模式,又稱工廠模式、多態工廠模式和虛擬構造器模式,通過定義工廠父類負責定義創建對象的公共接口,而子類則負責生成具體的對象。是在工廠模式家族中是用的最多模式,一般項目中存在最多的就是這個模式。是對簡單工廠模式的一個優化,讓每個對象都有一個與之對應的工廠。
這裡我們接着用上面的例子,假設這家餐廳的生意非常好,所以餐館的老闆把餐館所有負責點餐的服務員都辭退了,取而代之的是添加了一個收銀台,然後讓每個廚師只負責做一樣菜。這樣客人只需要和收銀台說要求就行了。
這裡我們接着用上面的類。除去服務員Waiter類
新建Cashier接口
/**
* @author codermy
* @createTime 2020/6/15
*/
public interface Cashier {
public Restaurant getFood();
}
然後給每一個菜品新建一個工廠類
EggCooker
/**
* @author codermy
* @createTime 2020/6/15
*/
public class EggCooker implements Cashier {
@Override
public Restaurant getFood() {
return new Egg();
}
}
MeetCooker
/**
* @author codermy
* @createTime 2020/6/15
*/
public class MeetCooker implements Cashier{
@Override
public Restaurant getFood() {
return new Meet();
}
}
然後顧客點單只需要在收銀台,餐廳的系統會自動將信息傳遞給相應的廚師,對應的廚師就能在餐館中把菜做好
/**
* @author codermy
* @createTime 2020/6/15
* 消費者
*/
public class Customer {
public static void main(String[] args) {
Cashier order = new EggCooker();
Restaurant food = order.getFood();
food.cook();
}
}
輸出結果
雞蛋羹做好了
工廠方法模式解決了簡單工廠模式不符合的開閉原則,當添加一個菜品時,只需要再僱傭一個廚師就行(從現實角度看,老闆有點虧哦)。但是這也增加了系統的複雜度(菜越多,廚師就越多,這哪家餐館頂的住)
抽象工廠模式
這個模式解決了每個工廠只能創建一類產品(工廠方法模式)的問題
這裡用餐館的例子不太形象,不是很容易理解,強行舉例可能會和上面的方法弄混,我自己繞了好一會,所以我們換一個例子。
現在我們人手不離手機,我們假設手機有如下幾個功能
//手機產品接口
public interface IphoneProduct {
void callup();//打電話
void sendSms();//發短訊
}
每個人家裡又都有路由器,路由器有如下功能
//路由器產品接口
public interface IRouterProduct {
void openwifi();//開啟wifi
void setting();//設置wifi
}
然後現在有一個抽象產品工廠,是來生產這兩樣產品的,假設生產手機和路由器的方法是一樣的,只是需要加上廠商信息
//抽象產品工廠
public interface IProductFactory {
//生產手機
IphoneProduct iphoneProduct();
//生產路由器
IRouterProduct iRouterProduct();
}
現在有兩家廠商,小米和華為工廠,可以生產手機和路由器,他們兩家廠商分別由兩條產業線來做手機和路由器
//小米手機
public class XiaomiPhone implements IphoneProduct{
@Override
public void callup() {
System.out.println("用小米手機打電話");
}
@Override
public void sendSms() {
System.out.println("用小米手機發短訊");
}
}
//小米路由器
public class XiaomiRouter implements IRouterProduct {
@Override
public void openwifi() {
System.out.println("打開小米wifi");
}
@Override
public void setting() {
System.out.println("設置小米wifi");
}
}
//小米廠商
public class XiaomiFactory implements IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new XiaomiRouter();
}
}
//華為手機
public class HuaweiPhone implements IphoneProduct {
@Override
public void callup() {
System.out.println("用華為手機打電話");
}
@Override
public void sendSms() {
System.out.println("用華為手機發短訊");
}
}
//華為路由器
public class HuaweiRouter implements IRouterProduct {
@Override
public void openwifi() {
System.out.println("打開華為wifi");
}
@Override
public void setting() {
System.out.println("設置華為wifi");
}
}
//華為工廠
public class HuaweiFactory implements IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new HuaweiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new HuaweiRouter();
}
}
消費者類
//消費者/測試類
public class Customer {
public static void main(String[] args) {
System.out.println("==============小米產品=================");
XiaomiFactory xiaomiFactory = new XiaomiFactory();//新建一個小米工廠
IphoneProduct xiaomiiphoneProduct = xiaomiFactory.iphoneProduct();//小米工廠開始生產小米手機
xiaomiiphoneProduct.callup();//測試小米手機打電話功能
IRouterProduct xiaomiiRouterProduct = xiaomiFactory.iRouterProduct();//小米工廠開始生產小米路由器
xiaomiiRouterProduct.openwifi();//測試小米路由器打開wifi功能
System.out.println("==============華為產品=================");
HuaweiFactory huaweiFactory = new HuaweiFactory();
IphoneProduct huaweiiphoneProduct1 = huaweiFactory.iphoneProduct();
huaweiiphoneProduct1.callup();
IRouterProduct huaweiiRouterProduct = huaweiFactory.iRouterProduct();
huaweiiRouterProduct.openwifi();
}
}
輸出
==============小米產品=================
用小米手機打電話
打開小米wifi
==============華為產品=================
用華為手機打電話
打開華為wifi
抽象工廠模式相較於以上兩種模式難以理解一些。這裡提供另一種寫法比較好理解,來自Guide哥的博客(以下所有內容)
不知道大家玩過穿越火線或者吃雞這類遊戲了嗎,遊戲中存在各種槍。我們假設現在存在AK、M4A1兩類槍,每一種槍對應一種子彈。我們現在這樣考慮生產AK的工廠可以順便生產AK使用的子彈,生產M4A1的工廠可以順便生產M4A1使用的子彈。(AK工廠生產AK系列產品包括子彈啊,AK槍的類型啊這些,M4A1工廠同理)
————————————————
(1)創建相關接口:
槍
public interface Gun {
public void shooting();
}
子彈
public interface Bullet {
public void load();
}
(2)創建接口對應實現類:
AK類
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
M4A1類
public class M4A1 implements Gun {
@Override
public void shooting() {
System.out.println("shooting with M4A1");
}
}
AK子彈類
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
M4A1子彈類
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
(3)創建工廠接口
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
(4)創建具體工廠
生產AK和AK子彈的工廠
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
生產M4A1和M4A1子彈的工廠
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
(5)測試
public class AK_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with AK");
}
}
輸出結果:
Load bullets with AK
shooting with AK