Java設計模式之工廠方法模式與抽象工廠模式

1、前期回顧

上一篇《Java設計模式之單例模式》詳細介紹了單例模式,介紹了單例模式的使用場景,優缺點,同時也寫了兩種常見的單例模式寫法,懶漢式單例模式和餓漢氏單例模式,固然,單例模式的寫法還有不少,好比,枚舉單例模式,靜態內部類單例模式等。有興趣的能夠自行查找資料。本篇開始介紹單例模式的第二篇,工廠方法模式,以及工廠模式的升級版,抽象工廠模式。java

2、工廠方法模式的定義與實踐

定義:Define an interface for creating an object,but let subclasses decide which class to instantiation.Factory Mehod lets a class defer instantiation to subclasses.翻譯過來就是,定義一個用於建立對象的接口,讓其子類決定實例化哪一個類。工廠方法讓一個類的實例化延遲到其子類。設計模式

上面的定義說明好像很繞口,若是不理解不要緊,咱們用個例子來講明這個定義:ide

//定義產品接口
public interface Iproduct {
    public void doSomething();
}
//產品實現類
public class ProductA implements Iproduct {
    @Override
    public void doSomething() {
        System.out.println("我是產品A,我能夠搞事情");
    }
}
//定義工廠類接口
public interface IFactory {
    //建立產品工廠方法
    < T extends Iproduct> T creatProduct(Class<T> clz);
}
//工廠方法實現類
public class ProductFactory implements IFactory {
    @Override
    public <T extends Iproduct> T creatProduct(Class<T> clz) {
        Iproduct product=null;
        try {
            product= clz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}
//場景類
public class Client {
    public static void main(String[] args) {
        IFactory factory=new ProductFactory();
        Iproduct product= factory.creatProduct(ProductA.class);
        product.doSomething();
    }
}

上述例子,實現了一個簡單的工廠方法模式,定義了一個工廠接口類,而後具體的工廠方法實現了建立對象的邏輯。看到這裏,有人確定會問,這裏要new一個工廠類的實例,和我new一個具體的對象有什麼區別呢?反正都要本身new,幹嗎要搞一個工廠類這麼繞呢?對,沒錯。這裏是要new一個工廠類,可是上面的例子建立產品的對象是比較簡單,因此感受不出來,若是ProductA的實例建立是一個很是複雜的過程,那麼這個時候我經過工廠方法模式建立對象的實例就很方便了。post

確定還有人問,我以爲上面這個方式還有點囉嗦,有沒有更簡便的方式實現工廠模式呢?答案是,有。咱們接下來看看簡單工廠模式。簡單工廠方法模式就是上述工廠方法模式的簡單版本。咱們只要把上述工廠類的接口去掉,而後把工廠實現類改成靜態類就能夠實現簡單工廠方法模式了。代碼是這樣的:.net

//這裏只去掉了接口,改成靜態方法
public class ProductFactory  {
    public static <T extends Iproduct> T creatProduct(Class<T> clz) {
        Iproduct product=null;
        try {
            product= clz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}

public class Client {
    public static void main(String[] args) {
        Iproduct product= ProductFactory.creatProduct(ProductA.class);
        product.doSomething();
    }
}

這裏就不用本身去new 工廠類啦,代碼也簡潔了不少。可是去掉了接口也就意味着後面的擴展是不友好的,因此違反了開閉原則。翻譯

3、抽象工廠模式的定義與實踐

定義:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.翻譯: 提供一個建立相關或者相互依賴的對象的接口,而且無需指定他們的具體實現類。設計

這裏理解可能有點困難,爲了便於理解,咱們先引入兩個概念。3d

產品等級結構: 產品等級結構即產品的繼承結構,如一個抽象類是汽車,其子類就是各個品牌的汽車,好比奔馳,寶馬汽車。汽車和奔馳就構成了一個產品等級結構,抽象汽車是父類,而具體品牌的汽車是其子類。code

產品族 : 在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不一樣產品等級結構中的一組產品,如奔馳工廠生產的奔馳跑車,寶馬公司生產的跑車,奔馳跑車位於奔馳產品等級結構中,寶馬跑車位於寶馬產品等級結構中。對象

因此,汽車和品牌是一個產品等級結構,而每一個品牌下面有多個產品線,也就是說奔馳牌下面的汽車有多個產品族,好比跑車族,SUV族。奔馳跑車和寶馬跑車是一個產品族,奔馳SUV和寶馬SUV是一個產品族。因此上面定義中「相關或者相互依賴的對象」就是場景中包含,同一個等級結構中有不一樣的產品族。 ,咱們來用一個實際場景來講明下。

假設,我須要一個汽車工廠,汽車能夠生產跑車和SUV車型,那麼這個時候用以前的工廠方法模式就不知足了,方法工廠模式只能知足生產一個產品,如今須要生產兩個產品。因此咱們在方法工廠模式的基礎上改造下來知足這個場景。

//汽車接口
public interface ICar {
     void dirver();
}
//抽象汽車類
public abstract class AbstractProduct implements ICar{
    @Override
    public void dirver() {
        System.out.println("我是汽車,我能夠開動");
    }

    /***
     * 展現不一樣車的亮點*/
    public abstract void showSpecial();
}
//寶馬SUV實現類
public class BmwSuv extends AbstractProduct {
    @Override
    public void showSpecial() {
        System.out.println("我是寶馬牌SUV,個人特色就是多功能用途");
    }
}
//寶馬跑車實現類
public class BmwProductRoadster extends AbstractProduct {
    @Override
    public void showSpecial() {
        System.out.println("我是寶馬跑車,個人特色就是跑的快");
    }
}
//奔馳SUV
public class BenzSuv extends AbstractProduct {
    @Override
    public void showSpecial() {
        System.out.println("我是奔馳牌SUV,個人特色就是多功能用途");
    }
}
//奔馳跑車
public class BenzProductRoadster extends AbstractProduct {
    @Override
    public void showSpecial() {
        System.out.println("我是奔馳跑車,個人特色就是跑的快");
    }
}

//抽象工廠類
public abstract class AbstractFactory {
    //建立跑車
    public abstract < T extends ICar> T createRoadster();
    //建立SUV
    public abstract < T extends ICar> T createSuv();
}
//奔馳汽車工廠類
public class BenzFactory extends AbstractFactory {
    @Override
    public <T extends ICar> T createRoadster() {
        return (T) new BenzProductRoadster();
    }

    @Override
    public <T extends ICar> T createSuv() {
        return (T) new BenzSuv();
    }
}
//寶馬汽車工廠類
public class BmwFactory extends AbstractFactory {
    @Override
    public <T extends ICar> T createRoadster() {
        return (T) new BmwProductRoadster();
    }

    @Override
    public <T extends ICar> T createSuv() {
        return (T) new BmwSuv();
    }
}
//場景類
public class Client {
    public static void main(String[] args) {
        AbstractFactory bmwFactory=new BmwFactory();
        AbstractFactory benzFactory=new BenzFactory();
        AbstractProduct bmwRoadster= bmwFactory.createRoadster();
        AbstractProduct bmwSuv=bmwFactory.createSuv();
        AbstractProduct benzRoadster=benzFactory.createRoadster();
        AbstractProduct benzSuv=benzFactory.createSuv();
        bmwRoadster.showSpecial();
        bmwSuv.showSpecial();
        benzRoadster.showSpecial();
        benzSuv.showSpecial();
    }
}

細心的讀者應該發現,咱們的改造相對於工廠方法模式而言,只是抽象工廠模式新增了多一個建立方法。這也是抽象工廠模式和工廠方法模式最明顯的區別,抽象工廠模式能夠知足多類型,多業務的場景,好比汽車工廠能夠生產多種類型汽車,就適用於抽象工廠模式。而普通工廠方法模式就是針對生產某一種對象而言比較適用。總結來講就是,抽象工廠模式適用於多產品族的狀況,普通工廠方法模式適用於單產品族狀況。

4、總結

上面介紹了工廠方法模式與抽象工廠模式的定義與實踐,同時也衍生了一個簡單工廠模式。咱們先來總結下工廠模式的優勢與缺點。

優勢:

1.良好的封裝性,代碼結構清晰,不用關注具體對象的建立過程,符合迪米特法則。

2.良好的擴展性,咱們擴展了產品,只要新建對應的工廠類,實現本身的實現邏輯便可。

缺點:

1.對於抽象工廠模式,產品族的擴展比較困難,須要修改頂部抽象工廠類,這會致使全部實現類都要修改,不符合開閉原則。

2.對於簡單工廠模式,因爲沒有接口和抽象父類的約束,從而也會致使擴展只能修改代碼,不符合開閉原則。

最後咱們列一個表格來總結下工廠方法模式,簡單工廠模式,抽象工廠模式的區別。

簡單工廠模式 工廠方法模式 抽象工廠模式
有無接口或抽象類
適用場景 通常不涉及擴展,單產品族 涉及單產品族,便於擴展 多產品族場景,能夠擴展等級結構,不便於擴展產品族
實現複雜度 最簡單 簡單 通常

5、參考

《設計模式之禪》

設計模式(三)抽象工廠模式

6、推薦閱讀

Java設計模式之單例模式

JAVA設計模式之開篇

帶你走進java集合之ArrayList

帶你走進java集合之HashMap

Java鎖之ReentrantLock(一)

Java鎖之ReentrantLock(二)

Java鎖之ReentrantReadWriteLock

相關文章
相關標籤/搜索