設(shè)計(jì)模式之工廠方法模式|抽象工廠模式

abstract.jpg

工廠方法模式(Factory Method)

工廠方法模式(Factory Method)是一種創(chuàng)建型的設(shè)計(jì)模式,在該模式中父類決定實(shí)例的生成方式。但是不決定它要生成的具體的類,具體的處理是交給子類完成的,這樣將生成實(shí)例的框架和負(fù)責(zé)生成實(shí)例的類解耦。

接下來通過一個(gè)制作身份證明的IDCard來學(xué)習(xí)工廠方法模式,照例先來一張類圖,對(duì)該例程序有大概的認(rèn)識(shí)。

類圖:

這里寫圖片描述

產(chǎn)品類Product

Product屬于工廠方法模式中的"產(chǎn)品"類,在該類中僅僅聲明了一個(gè)抽象方法use(),定義了任意產(chǎn)品都可以u(píng)se的方法,即定義了生成的實(shí)例所持有的接口方法。

public abstract class Product {
    public abstract void use();
}

工廠類Factory

該類是生產(chǎn)Product的類,該類內(nèi)部提供了一個(gè)create方法創(chuàng)建產(chǎn)品,并且提供抽象方法createProduct創(chuàng)建產(chǎn)品和registerProduct注冊(cè)產(chǎn)品。他在工廠方法模式充當(dāng)創(chuàng)建者這一角色,負(fù)責(zé)生成產(chǎn)品Product,但是具體處理交由具體創(chuàng)建者。對(duì)于使用生成實(shí)例的專用方法createProduct創(chuàng)建實(shí)例,而不用new關(guān)鍵字來生成,這樣做的好處是可以防止
父類與其他類耦合。

public abstract class Factory {
    public final Product create(String owner) {
        Product p = createProduct(owner);
        registerProduct(p);
        return p;
    }
    protected abstract Product createProduct(String owner);
    protected abstract void registerProduct(Product product);
}

具體產(chǎn)品類IDCard

在上面說到產(chǎn)品類Product,它需要子類去實(shí)現(xiàn)具體的產(chǎn)品IDCard,而IDCard和Product是分離的。

public class IDCard extends Product {
    private String owner;
    IDCard(String owner) {
        System.out.println("制作ID卡"+owner);
        this.owner = owner;
    }
    public void use() {
        System.out.println("使用ID卡"+owner);
    }
    public String getOwner() {
        return owner;
    }
}

具體工廠類IDCardFactory

IDCardFactory是工廠類Factory的具體實(shí)現(xiàn),通過createProduct方法生成具體的產(chǎn)品,并通過registerProduct方法將有owner生成的具體產(chǎn)品IDCard保存到owners實(shí)現(xiàn)產(chǎn)品注冊(cè)。

public class IDCardFactory extends Factory {
    private List owners = new ArrayList();
    protected  Product createProduct(String owner) {
        return new IDCard(owner);
    }
    protected void registerProduct(Product product) {
        IDCard card = (IDCard)product;
        owners.add(card.getOwner());
    }
    public List getOwners() {
        return owners;
    }
}

測試類Main

public class Main {
    public static void main(String[] args) {
        Factory factory = new IDCardFactory();
        Product card1 = factory.create("小明");
        Product card2 = factory.create("小紅");
        Product card3 = factory.create("小剛");
        card1.use();
        card2.use();
        card3.use();
    }
}

輸出信息

制作ID卡小明
制作ID卡小紅
制作ID卡小剛
使用ID卡小明
使用ID卡小紅
使用ID卡小剛

在上面的介紹中我們的需求是生產(chǎn)一個(gè)IDCard,那么如果我們生成一個(gè)電視機(jī)呢,我們只需要?jiǎng)?chuàng)建一個(gè)電視機(jī)Televison和生成電視機(jī)的具體工廠類TelevisionFactory,在此,我們不需要修改產(chǎn)品類Product和工廠類Factory,就可以創(chuàng)建我們需要的產(chǎn)品。

抽象工廠模式

在上面的工廠方法中具體的產(chǎn)品和具體的工廠是一一對(duì)應(yīng)的,一個(gè)工廠只能生產(chǎn)一種產(chǎn)品,結(jié)構(gòu)單一,例如小米公司剛開始是只生產(chǎn)小米手機(jī),但是伴隨著公司的發(fā)展,他們需要生產(chǎn)不同型號(hào)的手機(jī),也會(huì)生產(chǎn)路由器,小米電視等等,那么工廠方法模式已不能滿足業(yè)務(wù)的需求了,此時(shí)我們就需要抽象工廠模式,即一個(gè)工廠可以生產(chǎn)多種產(chǎn)品。(當(dāng)然使用工廠方法也是可以的,不過需要?jiǎng)?chuàng)建多個(gè)具體工廠)
在抽象工廠模式中引入兩個(gè)重要的概念一個(gè)是產(chǎn)品等級(jí)結(jié)構(gòu),它是產(chǎn)品的繼承結(jié)構(gòu)例如一個(gè)抽象產(chǎn)品電視類它的子類可以為各種型號(hào)或的電視。那么產(chǎn)品族是什么呢?在上面提到小米可以生產(chǎn)手機(jī),電視,路由器等,那么這些就是一個(gè)產(chǎn)品族。

在圖解設(shè)計(jì)模式一書中,是通過將帶有層次結(jié)構(gòu)關(guān)系的集合標(biāo)簽制成HTML文件的示例講解抽象工廠模式的,不過我感覺示例代碼稍微有點(diǎn)多,所以基于自己的理解,通過開始所說的小米生產(chǎn)手機(jī)和電視的這個(gè)例子來總結(jié)抽象工廠模式。

照例先看類圖:

這里寫圖片描述

抽象產(chǎn)品

抽象產(chǎn)品角色負(fù)責(zé)定義抽象工廠生成的產(chǎn)品的接口,在本例中有兩個(gè)抽象產(chǎn)品類,分別是手機(jī)和電視的抽象類,對(duì)應(yīng)有一個(gè)打電話dial()和watchTV()方法

public abstract class IMobilePhone {
    public abstract void dial();
}
public abstract class ITelevision {
    public abstract void watchTV();
}

具體產(chǎn)品類

具體產(chǎn)品角色負(fù)責(zé)實(shí)現(xiàn)抽象產(chǎn)品角色的接口。

public class MobilePhone extends IMobilePhone {
    private String name;
    public MobilePhone(String name) {
        this.name=name;
        System.out.println("制作手機(jī)"+name);
    }

    @Override
    public void dial() {
        System.out.println("使用"+name+"打電話");
    }
}


public class Television extends ITelevision {
    private String name;
    public Television(String name) {
        this.name=name;
        System.out.println("制作電視"+name);
    }

    @Override
    public void watchTV() {
        System.out.println("通過"+name+"看電視");
    }
}

抽象工廠類

抽象工廠角色是負(fù)責(zé)定義用于生成抽象產(chǎn)品的接口。

public abstract class Factory {
    public static Factory getFactory(String classname) {
        Factory factory = null;
        try {
            factory = (Factory)Class.forName(classname).newInstance();
        } catch (ClassNotFoundException e) {
            System.err.println("沒有找到 " + classname + "類。");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }
    public abstract MobilePhone createMobilePhone(String type);
    public abstract Television createTelevision(String type);
}

具體工廠

實(shí)現(xiàn)抽象工廠的抽象方法生成產(chǎn)品。

public class XiaoMiFactory extends  Factory{
    @Override
    public MobilePhone createMobilePhone(String type) {
        return new MobilePhone(type);
    }
    @Override
    public Television createTelevision(String type) {
        return new Television(type);
    }
}

測試類

public class Main {
    public static void main(String[] args) {
        Factory factory = Factory.getFactory("com.abstractfactory.XiaoMiFactory");
        IMobilePhone mobilePhone1=factory.createMobilePhone("小米2");
        IMobilePhone mobilePhone2=factory.createMobilePhone("小米5");

        ITelevision television1=factory.createTelevision("小米電視2");
        ITelevision television2=factory.createTelevision("小米電視3");

        mobilePhone1.dial();
        mobilePhone2.dial();

        television1.watchTV();
        television2.watchTV();

    }
}

輸出信息

制作手機(jī)小米2
制作手機(jī)小米5
制作電視小米電視2
制作電視小米電視3
使用小米2打電話
使用小米5打電話
通過小米電視2看電視
通過小米電視3看電視

兩者關(guān)系分析

對(duì)于工廠方法它是通過類繼承創(chuàng)建抽象產(chǎn)品,并且是創(chuàng)建一種產(chǎn)品,如果創(chuàng)建新的產(chǎn)品,只需新建一個(gè)工廠重載工廠方法以創(chuàng)建新的產(chǎn)品。

在抽象工廠模式中,它實(shí)現(xiàn)了具體類生成的分離,因此增加具體工廠變的很簡單,例如現(xiàn)在華為也生產(chǎn)手機(jī)和電視,我們只需要?jiǎng)?chuàng)建具體的工廠類就可以了。對(duì)于工廠類抽象工廠模式是很容易增加的,但是如果小米公司現(xiàn)在業(yè)務(wù)又拓展了,開始做機(jī)器人,這樣就困難了,我們需要將所有的工廠做修改,新增創(chuàng)建機(jī)器人的方法,如果之前工廠類很多,那么這個(gè)工作量就會(huì)很大了。

總而言之,這兩種都是工廠模式,形式上很相似,最終的目的都是為了解耦,實(shí)現(xiàn)低耦合。而且它們之間很容易互相轉(zhuǎn)換,當(dāng)我們使用工廠模式后可能加了一個(gè)方法就成為了抽象工廠模式。不管你如何使用,只有達(dá)到我們代碼低耦合,清晰明了的目的就可以。當(dāng)然這是個(gè)人感覺。

好了,自己關(guān)于工廠模式的理解到這里已經(jīng)總結(jié)完畢了。有問題歡迎留言指出,Have a wonderful day .

如需文章中所寫代碼,請(qǐng)移步GitHub查看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 設(shè)計(jì)原則: 要依賴抽象,不要依賴具體類 目錄 本文的結(jié)構(gòu)如下: 什么是抽象工廠模式 為什么要用該模式 模式的結(jié)構(gòu) ...
    w1992wishes閱讀 1,236評(píng)論 0 6
  • 1 場景問題# 1.1 導(dǎo)出數(shù)據(jù)的應(yīng)用框架## 考慮這樣一個(gè)實(shí)際應(yīng)用:實(shí)現(xiàn)一個(gè)導(dǎo)出數(shù)據(jù)的應(yīng)用框架,來讓客戶選擇數(shù)據(jù)...
    七寸知架構(gòu)閱讀 7,011評(píng)論 6 75
  • 簡單工廠模式雖然簡單,但存在一個(gè)很嚴(yán)重的問題。當(dāng)系統(tǒng)中需要引入新產(chǎn)品時(shí),由于靜態(tài)工廠方法通過所傳入?yún)?shù)的不同來創(chuàng)建...
    justCode_閱讀 1,305評(píng)論 1 9
  • 為了避免清明假期的人流高峰,大宇特意買了假期前兩天的火車票。他要陪女朋友萌萌回家給萌萌的媽媽掃墓。 今天是坐車的...
    豆粉膜好好吃閱讀 498評(píng)論 3 2
  • 有沒有那么一首民謠,在你聽的時(shí)候想起一個(gè)人,一個(gè)地方,一個(gè)故事?有沒有那么一句歌詞,它勾勒出了你記憶的輪廓...
    Joey冰閱讀 827評(píng)論 0 1

友情鏈接更多精彩內(nèi)容