這是我設(shè)計模式系列的第一篇總結(jié)萨脑。
首先講一下為什么需要使用工廠設(shè)計模式沈堡?
我們平時正常開發(fā)編碼的時候創(chuàng)建對象有幾種方式:
1.直接new
2.使用Class類的newInstance方法
3.使用Constructor類的newInstance方法
4.使用clone
5.使用序列化
最常見的就是第一種new的方式罗岖。但是有的時候往往創(chuàng)建對象和使用對象在同一個類當(dāng)中风纠。這就導(dǎo)致了這個類的任務(wù)很繁重,并且職責(zé)不清晰。并且違反了"開閉原則"。所以我們就要把創(chuàng)建對象和使用對象兩個職責(zé)分離開,這樣我們就引入了“工廠”的概念迟隅。我們把創(chuàng)建對象的任務(wù)交給“工廠”來做,什么時候用就直接從工廠中拿励七。
我們常說的工廠設(shè)計模式有“簡單工廠模式”智袭、“工廠模式”、和“抽象工廠模式”掠抬。
工廠三兄弟我從簡單到復(fù)雜(簡單到抽象)進(jìn)行總結(jié)吼野。
一.簡單工廠模式
簡單工廠模式定義如下:
簡單工廠模式(Simple Factory Pattern):定義一個工廠類,它可以根據(jù)參數(shù)的不同返回不同類的實例两波,被創(chuàng)建的實例通常都具有共同的父類瞳步。因為在簡單工廠模式中用于創(chuàng)建實例的方法是靜態(tài)(static)方法闷哆,因此簡單工廠模式又被稱為靜態(tài)工廠方法(Static Factory Method)模式,它屬于類創(chuàng)建型模式谚攒。
我們圍繞著一個購買Nike和Adidas產(chǎn)品的例子實現(xiàn)接下來的三種工廠模式。
首先簡單工廠模式顧名思義他的結(jié)構(gòu)比較簡單氛堕,那么適用于需要的對象比較少并且簡單的情況下馏臭。
1.Shoes 抽象產(chǎn)品接口:這個接口代表了所有工廠最終生產(chǎn)出具體類的父類。
2.NikeShoes讼稚、AdidasShoes 具體產(chǎn)品實現(xiàn)類:抽象產(chǎn)品接口的實現(xiàn)類括儒,這里包含了具體方法的實現(xiàn)、自己的構(gòu)造方法锐想、初始化一些信息等帮寻。
3.ShoesFactory 工廠方法類:整個當(dāng)中最核心的類。此類包含了選擇創(chuàng)建對象的邏輯赠摇。
//抽象產(chǎn)品接口
public interface Shoes {
//共有方法
void display();
}
//Nike商品
public class NikeShoes implements Shoes {
@Override
public void display() {
System.out.println("耐克鞋~~~");
}
}
//Adidas商品
public class AdidasShoes implements Shoes {
@Override
public void display() {
System.out.println("阿迪達(dá)斯鞋~~~");
}
}
//工廠
public class ShoesFactory {
public static Shoes getShoes(String brand) {
if (brand.equalsIgnoreCase("nike")) {
return new NikeShoes();
} else if (brand.equalsIgnoreCase("adidas")) {
return new AdidasShoes();
} else {
return null;
}
}
}
//購買鞋子入口函數(shù)
public class BuyShoes {
public static void main(String args[]) {
Shoes shoes = ShoesFactory.getShoes("nike");
shoes.display();
}
}
//輸出
-------------
//耐克鞋~~~
我們可以看到這個工廠類通過傳入的參數(shù)來選擇創(chuàng)建具體類型的對象并且返回固逗。
二.工廠方法模式
接下來是工廠三兄弟的老二——“工廠方法模式”。
這個老二又是怎樣的需求促使它誕生的呢藕帜?
我們回憶一下剛才的老三"簡單工廠模式"烫罩,它適用于創(chuàng)建的對象類型較少的情況下。但是它有一個致命的缺點就是工廠類中的任務(wù)太重了洽故,如果對象的類型較多贝攒,則需要寫很多的if... else...,如果某一個類型改變了时甚,就要回過頭來去修改工廠中的邏輯代碼隘弊,這樣很不方便。把簡單工廠稍微抽象一下荒适,就誕生了我們的工廠方法模式來解決這樣的問題梨熙。
工廠方法模式定義:
工廠方法模式(Factory Method Pattern):定義一個用于創(chuàng)建對象的接口,讓子類決定將哪一個類實例化刀诬。工廠方法模式讓一個類的實例化延遲到其子類串结。工廠方法模式又簡稱為工廠模式(Factory Pattern),又可稱作虛擬構(gòu)造器模式(Virtual Constructor Pattern)或多態(tài)工廠模式(Polymorphic Factory Pattern)舅列。工廠方法模式是一種類創(chuàng)建型模式肌割。
1.ShoesFactory 抽象工廠:有別于簡單工廠這里多了一個“抽象工廠”接口。接口中聲明了創(chuàng)建具體產(chǎn)品的方法帐要。返回值是抽象的產(chǎn)品接口類型把敞。
2.NikeShoesFactory、AdidasShoesFactory 具體工廠類:實現(xiàn)抽象工廠接口榨惠,并實現(xiàn)創(chuàng)建對象的方法奋早,各個不同的具體工廠生產(chǎn)自己的具體產(chǎn)品盛霎。
3.產(chǎn)品接口和實現(xiàn)類與簡單工廠幾乎相同。
package Factory;
//抽象商品接口
public interface Shoes {
void display();
}
//Nike商品實現(xiàn)類
public class NikeShoes implements Shoes {
@Override
public void display() {
System.out.println("耐克鞋~~~");
}
}
//Adidas商品實現(xiàn)類
public class AdidasShoes implements Shoes {
@Override
public void display() {
System.out.println("阿迪達(dá)斯鞋~~~");
}
}
//抽象工廠
public interface ShoesFactory {
Shoes getShoes();
}
// Nike工廠
public class NikeShoesFactory implements ShoesFactory {
@Override
public Shoes getShoes() {
return new NikeShoes();
}
}
// Adidas工廠
public class AdidasShoesFactory implements ShoesFactory {
@Override
public Shoes getShoes() {
return new AdidasShoes();
}
}
//購買函數(shù)
public class BuyShoes {
public static void main(String args[]) {
ShoesFactory nikeShoesFactory = new NikeShoesFactory();
Shoes nikeShoes = nikeShoesFactory.getShoes();
nikeShoes.display();
ShoesFactory adidasShoesFactory = new AdidasShoesFactory();
Shoes adidasShoes = adidasShoesFactory.getShoes();
adidasShoes.display();
}
}
//輸出
-----------
//耐克鞋~~~
//阿迪達(dá)斯鞋~~~
我們可以看到這種優(yōu)化后的模式具體的產(chǎn)品從相對應(yīng)的具體工廠生產(chǎn)耽装,如果有新的產(chǎn)品愤炸,就橫向增加新的工廠即可,刪除同理不會橫向縱向的影響代碼結(jié)構(gòu)规个,滿足的了"開閉原則"。
那么我們想想這樣的模式還存在什么弊端呢姓建?
三.抽象工廠
工廠三兄弟的老大诞仓,也是真正Gof23種設(shè)計模式之一的"抽象工廠"模式。
定義:
抽象工廠模式(Abstract Factory Pattern):提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口速兔,而無須指定它們具體的類墅拭。抽象工廠模式又稱為Kit模式,它是一種對象創(chuàng)建型模式涣狗。
假設(shè)現(xiàn)在對象類型變得復(fù)雜橫向縱向兩個緯度都要擴(kuò)展谍婉?如下圖所示。
按照老二工廠方法模式的思想镀钓。定義一個抽象工廠接口屡萤,每一個具體商品會實現(xiàn)對應(yīng)的工廠類,那么就有了2*3=6種工廠類掸宛,如果在繼續(xù)擴(kuò)展工廠實現(xiàn)類會變得很多很繁雜死陆,所以為了解決這種問題,我們在工廠方法模式上再抽象一層概念唧瘾。
這樣我們只需要兩個具體工廠就能生產(chǎn)6種產(chǎn)品了措译。
//抽象產(chǎn)品——鞋子
public interface Shoes {
void displayShoes();
}
//抽象產(chǎn)品——褲子
public interface Pants {
void displayPants();
}
//抽象產(chǎn)品——衣服
public interface Clothes {
void displayClothes();
}
//具體產(chǎn)品——耐克鞋子
public class NikeShoes implements Shoes {
@Override
public void displayShoes() {
System.out.println("耐克鞋~~~");
}
}
//具體產(chǎn)品——耐克衣服
public class NikeClothes implements Clothes {
@Override
public void displayClothes() {
System.out.println("耐克衣服~~~");
}
}
//具體產(chǎn)品——耐克褲子
public class NikePants implements Pants {
@Override
public void displayPants() {
System.out.println("耐克褲子~~~");
}
}
//具體產(chǎn)品——阿迪鞋子
public class AdidasShoes implements Shoes {
@Override
public void displayShoes() {
System.out.println("阿迪達(dá)斯鞋子~~~");
}
}
//具體產(chǎn)品——阿迪衣服
public class AdidasClothes implements Clothes{
@Override
public void displayClothes() {
System.out.println("阿迪達(dá)斯衣服~~~");
}
}
//具體產(chǎn)品——阿迪褲子
public class AdidasPants implements Pants {
@Override
public void displayPants() {
System.out.println("阿迪達(dá)斯褲子~~~");
}
}
//抽象工廠
public interface AbstractFactory {
Shoes getShoes();
Clothes getClothes();
Pants getPants();
}
//耐克工廠
public class NikeFactory implements AbstractFactory {
@Override
public Shoes getShoes() {
return new NikeShoes();
}
@Override
public Clothes getClothes() {
return new NikeClothes();
}
@Override
public Pants getPants() {
return new NikePants();
}
}
//阿迪工廠
public class AdidasFactory implements AbstractFactory {
@Override
public Shoes getShoes() {
return new AdidasShoes();
}
@Override
public Clothes getClothes() {
return new AdidasClothes();
}
@Override
public Pants getPants() {
return new AdidasPants();
}
}
public class Shopping {
public static void main(String args[]) {
AbstractFactory nikeFactory = new NikeFactory();//可通過配置文件獲得
Shoes nikeShoes = nikeFactory.getShoes();
nikeShoes.displayShoes();
Clothes nikeClothes = nikeFactory.getClothes();
nikeClothes.displayClothes();
AbstractFactory adidasFatory = new AdidasFactory();
Shoes adidasShoes = adidasFatory.getShoes();
adidasShoes.displayShoes();
Pants adidasPants = adidasFatory.getPants();
adidasPants.displayPants();
}
}
//輸出
-------------------
//耐克鞋~~~
//耐克衣服~~~
//阿迪達(dá)斯鞋子~~~
//阿迪達(dá)斯褲子~~~
例子雖然簡單,但是想要應(yīng)用實際用的好還是需要多加練習(xí)的饰序。越抽象的方法越難理解但應(yīng)用越廣泛领虹。抽象工廠方法也有缺點。它不適合架構(gòu)設(shè)計好后頻繁修改求豫,因為橫向縱向都擴(kuò)展了以后必然存在“牽一發(fā)而動全身”的影響塌衰。所以要想把設(shè)計模式應(yīng)用的巧妙靈活,真的是一門需要慢慢修煉的“內(nèi)功”