工廠模式
工廠模式介紹
工廠模式是我們最常用的實(shí)例化對(duì)象模式了烹看,是用工廠方法代替new操作的一種模式国拇。著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程序系統(tǒng)可以說是隨處可見惯殊。因?yàn)楣S模式就相當(dāng)于創(chuàng)建實(shí)例對(duì)象的new酱吝,我們經(jīng)常要根據(jù)類Class生成實(shí)例對(duì)象,如A a=new A() 工廠模式也是用來創(chuàng)建實(shí)例對(duì)象的土思,所以以后new時(shí)就要多個(gè)心眼务热,是否可以考慮使用工廠模式,雖然這樣做己儒,可能多做一些工作崎岂,但會(huì)給你系統(tǒng)帶來更大的可擴(kuò)展性和盡量少的修改量。(百度百科)
工廠模式又分為:
- 簡(jiǎn)單工廠模式:允許接口創(chuàng)建對(duì)象闪湾,但不會(huì)暴露對(duì)象的創(chuàng)建邏輯冲甘。
- 工廠方法模式: 允許接口創(chuàng)建對(duì)象,但使用哪個(gè)類來創(chuàng)建對(duì)象途样,則是交由子類決定的
- 抽象方法模式: 抽象工廠是一個(gè)能夠創(chuàng)建一系列相關(guān)的對(duì)象而無需指定/公開其具體類的接口江醇。該模式能夠提供其他工廠的對(duì)象,在其內(nèi)部創(chuàng)建其他對(duì)象何暇。
簡(jiǎn)單工廠模式
屬于創(chuàng)建型模式陶夜,又叫做靜態(tài)工廠方法模式,不屬于23種GOF設(shè)計(jì)模式之一赖晶。是由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例律适。違背“開放 - 關(guān)閉原則”,一旦添加新產(chǎn)品就不得不修改工廠類的邏輯遏插,這樣就會(huì)造成工廠邏輯過于復(fù)雜捂贿。
假設(shè)現(xiàn)在有一家餐館
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("紅燒肉做好了");
}
}
餐館里有服務(wù)員,來負(fù)責(zé)向后廚傳達(dá)客人的需求
public class Waiter {
//同樣可以定義常量然后通過switch語句來實(shí)現(xiàn)
public static Restaurant getFood(String orderType) {
Restaurant restaurant = null;
if(orderType.equals("紅燒肉")){
restaurant = new Meet();
}else if (orderType.equals("雞蛋羹")){
restaurant = new Egg();
}
return restaurant;
}
}
現(xiàn)在顧客來了胳嘲,要點(diǎn)一份紅燒肉厂僧,就只需要和服務(wù)員說就行
public class Customer {
public static void main(String[] args) {
Restaurant restaurant = Waiter.getFood("紅燒肉");
restaurant.cook();
}
}
輸出
紅燒肉做好了
通過以上方法,的確實(shí)現(xiàn)了 提供創(chuàng)建實(shí)例的功能了牛,而無需關(guān)心具體實(shí)現(xiàn)颜屠。但是我們不難發(fā)現(xiàn),這種方法的擴(kuò)展性很差鹰祸,如果餐館新出了一款菜品甫窟,還需要我們?cè)诜?wù)員方法里修改。這使得當(dāng)餐館的菜品很多時(shí)蛙婴,工廠方法代碼邏輯將會(huì)非常復(fù)雜
工廠方法模式
工廠方法模式粗井,又稱工廠模式、多態(tài)工廠模式和虛擬構(gòu)造器模式街图,通過定義工廠父類負(fù)責(zé)定義創(chuàng)建對(duì)象的公共接口浇衬,而子類則負(fù)責(zé)生成具體的對(duì)象。是在工廠模式家族中是用的最多模式餐济,一般項(xiàng)目中存在最多的就是這個(gè)模式耘擂。是對(duì)簡(jiǎn)單工廠模式的一個(gè)優(yōu)化,讓每個(gè)對(duì)象都有一個(gè)與之對(duì)應(yīng)的工廠絮姆。
這里我們接著用上面的例子醉冤,假設(shè)這家餐廳的生意非常好,所以餐館的老板把餐館所有負(fù)責(zé)點(diǎn)餐的服務(wù)員都辭退了滚朵,取而代之的是添加了一個(gè)收銀臺(tái)冤灾,然后讓每個(gè)廚師只負(fù)責(zé)做一樣菜。這樣客人只需要和收銀臺(tái)說要求就行了辕近。
這里我們接著用上面的類韵吨。除去服務(wù)員Waiter類
新建Cashier接口
/**
* @author codermy
* @createTime 2020/6/15
*/
public interface Cashier {
public Restaurant getFood();
}
然后給每一個(gè)菜品新建一個(gè)工廠類
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();
}
}
然后顧客點(diǎn)單只需要在收銀臺(tái),餐廳的系統(tǒng)會(huì)自動(dòng)將信息傳遞給相應(yīng)的廚師移宅,對(duì)應(yīng)的廚師就能在餐館中把菜做好
/**
* @author codermy
* @createTime 2020/6/15
* 消費(fèi)者
*/
public class Customer {
public static void main(String[] args) {
Cashier order = new EggCooker();
Restaurant food = order.getFood();
food.cook();
}
}
輸出結(jié)果
雞蛋羹做好了
工廠方法模式解決了簡(jiǎn)單工廠模式不符合的開閉原則归粉,當(dāng)添加一個(gè)菜品時(shí),只需要再雇傭一個(gè)廚師就行(從現(xiàn)實(shí)角度看漏峰,老板有點(diǎn)虧哦)糠悼。但是這也增加了系統(tǒng)的復(fù)雜度(菜越多,廚師就越多浅乔,這哪家餐館頂?shù)淖倔喂。?/p>
抽象工廠模式
這個(gè)模式解決了每個(gè)工廠只能創(chuàng)建一類產(chǎn)品(工廠方法模式)的問題
這里用餐館的例子不太形象铝条,不是很容易理解,強(qiáng)行舉例可能會(huì)和上面的方法弄混席噩,我自己繞了好一會(huì)班缰,所以我們換一個(gè)例子。
現(xiàn)在我們?nèi)耸植浑x手機(jī)悼枢,我們假設(shè)手機(jī)有如下幾個(gè)功能
//手機(jī)產(chǎn)品接口
public interface IphoneProduct {
void callup();//打電話
void sendSms();//發(fā)短信
}
每個(gè)人家里又都有路由器埠忘,路由器有如下功能
//路由器產(chǎn)品接口
public interface IRouterProduct {
void openwifi();//開啟wifi
void setting();//設(shè)置wifi
}
然后現(xiàn)在有一個(gè)抽象產(chǎn)品工廠,是來生產(chǎn)這兩樣產(chǎn)品的馒索,假設(shè)生產(chǎn)手機(jī)和路由器的方法是一樣的莹妒,只是需要加上廠商信息
//抽象產(chǎn)品工廠
public interface IProductFactory {
//生產(chǎn)手機(jī)
IphoneProduct iphoneProduct();
//生產(chǎn)路由器
IRouterProduct iRouterProduct();
}
現(xiàn)在有兩家廠商,小米和華為工廠绰上,可以生產(chǎn)手機(jī)和路由器旨怠,他們兩家廠商分別由兩條產(chǎn)業(yè)線來做手機(jī)和路由器
//小米手機(jī)
public class XiaomiPhone implements IphoneProduct{
@Override
public void callup() {
System.out.println("用小米手機(jī)打電話");
}
@Override
public void sendSms() {
System.out.println("用小米手機(jī)發(fā)短信");
}
}
//小米路由器
public class XiaomiRouter implements IRouterProduct {
@Override
public void openwifi() {
System.out.println("打開小米wifi");
}
@Override
public void setting() {
System.out.println("設(shè)置小米wifi");
}
}
//小米廠商
public class XiaomiFactory implements IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new XiaomiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new XiaomiRouter();
}
}
//華為手機(jī)
public class HuaweiPhone implements IphoneProduct {
@Override
public void callup() {
System.out.println("用華為手機(jī)打電話");
}
@Override
public void sendSms() {
System.out.println("用華為手機(jī)發(fā)短信");
}
}
//華為路由器
public class HuaweiRouter implements IRouterProduct {
@Override
public void openwifi() {
System.out.println("打開華為wifi");
}
@Override
public void setting() {
System.out.println("設(shè)置華為wifi");
}
}
//華為工廠
public class HuaweiFactory implements IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new HuaweiPhone();
}
@Override
public IRouterProduct iRouterProduct() {
return new HuaweiRouter();
}
}
消費(fèi)者類
//消費(fèi)者/測(cè)試類
public class Customer {
public static void main(String[] args) {
System.out.println("==============小米產(chǎn)品=================");
XiaomiFactory xiaomiFactory = new XiaomiFactory();//新建一個(gè)小米工廠
IphoneProduct xiaomiiphoneProduct = xiaomiFactory.iphoneProduct();//小米工廠開始生產(chǎn)小米手機(jī)
xiaomiiphoneProduct.callup();//測(cè)試小米手機(jī)打電話功能
IRouterProduct xiaomiiRouterProduct = xiaomiFactory.iRouterProduct();//小米工廠開始生產(chǎn)小米路由器
xiaomiiRouterProduct.openwifi();//測(cè)試小米路由器打開wifi功能
System.out.println("==============華為產(chǎn)品=================");
HuaweiFactory huaweiFactory = new HuaweiFactory();
IphoneProduct huaweiiphoneProduct1 = huaweiFactory.iphoneProduct();
huaweiiphoneProduct1.callup();
IRouterProduct huaweiiRouterProduct = huaweiFactory.iRouterProduct();
huaweiiRouterProduct.openwifi();
}
}
輸出
==============小米產(chǎn)品=================
用小米手機(jī)打電話
打開小米wifi
==============華為產(chǎn)品=================
用華為手機(jī)打電話
打開華為wifi
抽象工廠模式相較于以上兩種模式難以理解一些。這里提供另一種寫法比較好理解蜈块,來自Guide哥的博客(以下所有內(nèi)容)
不知道大家玩過穿越火線或者吃雞這類游戲了嗎运吓,游戲中存在各種槍。我們假設(shè)現(xiàn)在存在AK疯趟、M4A1兩類槍拘哨,每一種槍對(duì)應(yīng)一種子彈。我們現(xiàn)在這樣考慮生產(chǎn)AK的工廠可以順便生產(chǎn)AK使用的子彈信峻,生產(chǎn)M4A1的工廠可以順便生產(chǎn)M4A1使用的子彈倦青。(AK工廠生產(chǎn)AK系列產(chǎn)品包括子彈啊,AK槍的類型啊這些盹舞,M4A1工廠同理)
————————————————
(1)創(chuàng)建相關(guān)接口:
槍
public interface Gun {
public void shooting();
}
子彈
public interface Bullet {
public void load();
}
(2)創(chuàng)建接口對(duì)應(yīng)實(shí)現(xiàn)類:
AK類
public class AK implements Gun{
@Override
public void shooting() {
System.out.println("shooting 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 M4A1_Bullet implements Bullet {
@Override
public void load() {
System.out.println("Load bullets with M4A1");
}
}
(3)創(chuàng)建工廠接口
public interface Factory {
public Gun produceGun();
public Bullet produceBullet();
}
(4)創(chuàng)建具體工廠
生產(chǎn)AK和AK子彈的工廠
public class AK_Factory implements Factory{
@Override
public Gun produceGun() {
return new AK();
}
@Override
public Bullet produceBullet() {
return new AK_Bullet();
}
}
生產(chǎn)M4A1和M4A1子彈的工廠
public class M4A1_Factory implements Factory{
@Override
public Gun produceGun() {
return new M4A1();
}
@Override
public Bullet produceBullet() {
return new M4A1_Bullet();
}
}
(5)測(cè)試
public class Test {
public static void main(String[] args) {
Factory factory;
Gun gun;
Bullet bullet;
factory =new AK_Factory();
bullet=factory.produceBullet();
bullet.load();
gun=factory.produceGun();
gun.shooting();
}
}
輸出結(jié)果:
Load bullets with AK
shooting with AK