23種設計模式之工廠方法模式、抽象工廠模式

一、簡單工廠模式(靜態工廠方法模式)

1.1 定義

定義一個工廠類,根據傳入的參數不一樣返回不一樣的實例,被建立的實例具備共同的父類或接口。23種設計模式並不包括簡單工廠模式,它更像一種編程習慣。編程

1.2 模式結構

簡單工廠模式由三部分組成:設計模式

  • 工廠類(Creator)角色:擔任這個角色的是簡單工廠模式的核心,含有與應用緊密相關的商業邏輯。工廠類在客戶端的直接調用下建立產品對象。
  • 抽象產品(AbstractProduct)角色:擔任這個角色的類是由簡單工廠模式所建立的對象的父類,或它們共同擁有的接口。
  • 具體產品(ConcreteProduct)角色:簡單工廠模式所建立的任何對象都是這個角色的實例。
1.3 實例

1.3.1 電視機父類TVbash

public abstract class TV {
    abstract void openTV();
}
複製代碼

1.3.2 海爾電視機和長虹電視機分別繼承TVide

public class HaierTV extends TV {
    public void openTV() {
        System.out.println("open haier TV");
    }
}
複製代碼
public class ChanghongTV extends TV {
    public void openTV() {
        System.out.println("open changhong TV");
    }
}
複製代碼

1.3.3 工廠類工具

public class Factory {

    public static TV watchTV(String type) throws Exception {
        if (type.equals("Haier")) {
            return new HaierTV();
        } else if (type.equals("Changhong")) {
            return new ChanghongTV();
        } else {
            throw new Exception();
        }
    }
}
複製代碼

1.3.4 客戶端調用ui

public class Test {
    
    public static void main(String[] args) throws Exception {
        TV tv = Factory.watchTV("Haier");
        tv.openTV();
    }
}
複製代碼
1.4 適用場景
  • 工廠類負責建立的對象比較小。
  • 客戶端只關心傳入工廠類的參數,不關心對象的建立過程。
1.5 在JDK中的應用

Calendar.class中的部分源碼:spa

private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale)
{
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                             .getCalendarProvider();
    if (provider != null) {
        try {
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
            // fall back to the default instantiation
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            switch (caltype) {
            case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
            }
        }
    }
    if (cal == null) {
        // If no known calendar type is explicitly specified,
        // perform the traditional way to create a Calendar:
        // create a BuddhistCalendar for th_TH locale,
        // a JapaneseImperialCalendar for ja_JP_JP locale, or
        // a GregorianCalendar for any other locales.
        // NOTE: The language, country and variant strings are interned.
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                   && aLocale.getCountry() == "JP") {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else {
            cal = new GregorianCalendar(zone, aLocale);
        }
    }
    return cal;
}
複製代碼
1.6 優缺點

1.6.1 優勢設計

  • 工廠類含有必要的判斷邏輯,能夠決定在何時建立哪個產品類的實例,客戶端能夠免除直接建立產品對象的責任,而僅僅「消費」產品;簡單工廠模式經過這種作法實現了對責任的分割,它提供了專門的工具類用於建立對象。
  • 客戶端無須知道所建立的具體產品類的類名,只須要知道產品類所對應的參數便可,對應一些複雜的類名,經過簡單工廠模式能夠減小使用者的記憶量。
  • 經過引入配置文件,能夠在不修改任何客戶端代碼的狀況下更換和增長新的具體產品類,在必定程度上提升了系統的靈活性。
  • 當須要引入新的產品是不須要修改客戶端的代碼,只須要添加相應的產品類並修改工廠類就能夠了,因此說從產品的角度上簡單工廠模式是符合「開-閉」原則的。

1.6.2 缺點code

  • 因爲工廠類集中了全部產品建立邏輯,工廠類通常被咱們稱做「全能類」或者「上帝類」,由於全部的產品建立它都完成,這看似是好事,但仔細想一想是有問題的。這樣一旦不能正常工做,整個系統都要受到影響。
  • 系統擴展困難,一旦添加新產品就要修改工廠邏輯,在產品類型較多時,有可能形成工廠邏輯過於複雜,不利於系統的擴展和維護。因此說從工廠的角度來講簡單工廠模式是不符合「開-閉」原則的。
  • 因爲使用靜態工廠方法,形成工廠角色沒法造成基於繼承的等級結構。

二、工廠方法模式(虛擬構造器模式、多態工廠模式)

2.1 定義

工廠父類負責定義建立產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣作的目的是將產品類的實例化操做延遲到工廠子類中完成,即經過工廠子類來肯定究竟應該實例化哪個具體產品類。orm

2.2 模式結構

工廠方法模式由四部分組成:

  • 抽象工廠(AbstractCreater)角色:擔任這個角色的是工廠方法模式的核心,與調用者直接交互用來提供產品。任何在模式中建立對象的工廠類必須繼承或者實現這個接口。
  • 具體工廠(ConcreteCreator)角色:擔任這個角色的是實現了抽象工廠接口的具體實現類。具體工廠角色含有與應用密切相關的邏輯,而且受到應用程序的調用以建立產品對象。
  • 抽象產品(AbstractProduct)角色:工廠方法模式所建立的對象的超類。主要目的是定義產品的規範,全部的產品實現都必須遵循這些規範。
  • 具體產品(ConcreteProduct)角色:實現了抽象產品角色所聲明的接口,工廠方法所建立的每個對象都是某個具體產品角色的實例。
2.3 實例

2.3.1 電視機父類TV

public abstract class TV {
    abstract void openTV();
}
複製代碼

2.3.2 海爾電視機和長虹電視機分別繼承TV

public class HaierTV extends TV {
    public void openTV() {
        System.out.println("open haier TV");
    }
}
複製代碼
public class Changhong extends TV {
    public void openTV() {
        System.out.println('open changhong TV');
    }
}
複製代碼

2.3.3 抽象工廠類

public abstract class Factory {
    public abstract TV watchTV();
}
複製代碼

2.3.4 具體工廠類

public class HaierFactory extends Factory {
    public TV watchTV() {
        return new HaierTV();
    }
}
複製代碼
public class ChanghongFactory extends Factory {
    public TV watchTV() {
        return new ChanghongTV();
    }
}
複製代碼

2.3.5 客戶端調用

public class Test {
    public static void main(String[] args) throws Exception {
        Factory factory = new HaierFactory();
        TV tv = factory.watchTV();
        tv.openTV();
    }
}
複製代碼
2.4 適用場景
  • 客戶端不須要知道它所場景的對象的類,只須要知道建立具體產品的工廠類。
  • 客戶端能夠經過子類來指定建立對應的對象。
2.5 優缺點
  • 工廠方法用來建立客戶所須要的產品,同時還向客戶隱藏了哪一種具體產品類將被實例化這一細節,用戶只須要關心所需產品對應的工廠,無須關心建立細節。
  • 基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它可以使工廠能夠自主肯定建立何種產品對象,而如何建立這個對象的細節則徹底封裝在具體工廠內部。
  • 在系統加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其餘的具體工廠和具體產品。這樣系統的可擴展性變得良好,徹底符合「開-閉「原則。

三、抽象工廠模式(Kit模式)

3.1 定義

提供一個建立一系列相關或相互依賴對象的接口,而無須指明它們具體的類。

3.2 產品族和等級等級結構
  • 產品等級結構:產品等級結構即產品的繼承結構,如一個抽象類是電視機,取子類有海爾電視機、長虹電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構。
  • 產品族:在抽象工廠模式中,產品族是指同一個工廠生產的,位於不一樣產品等級結構中的一組產品,如海爾電器工廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中。

3.3 模式結構

抽象工廠模式和工廠方法模式相似都是四部分組成的,不一樣的是,抽象工廠模式中具體工廠再也不是隻建立一種產品,一個具體的工廠能夠建立一個產品族的產品。

3.4 實例

3.4.1 電視機父類TV

public abstract class TV {
    abstract void openTV();
}
複製代碼

3.4.2 海爾電視機和長虹電視機分別繼承TV

public class HaireTV extends TV {
    public void openTV() {
        System.out.println("open haire TV");
    }
}
複製代碼
public class ChanghongTV extends TV {
    public void openTV() {
        System.out.println('open changhong TV');
    }
}
複製代碼

3.4.3 冰箱父類Refrigerator

public abstract class Refrigerator {
    abstract void openRefrigerator();
}
複製代碼

3.4.4 海爾冰箱和長虹冰箱分別繼承Refrigerator

public class HaierRefrigerator extends Refrigerator {
    public void openRefrigerator() {
        System.out.println("open haier refrigerator");
    }
}
複製代碼
public class ChanghongRefrigerator extends Refrigerator {
    public void openRefrigerator() {
        System.out.println("open changhong refrigerator");
    }
}
複製代碼

3.4.5 抽象工廠類,定義同一族產品的兩個不一樣等級結構的產品結構

public abstract class Factory {
    public abstract TV watchTV();
    public abstract Refrigerator takeThings();
}
複製代碼

3.4.6 具體工廠類

public class HaierFactory extends Factory {
    public TV watchTV() {
        return new HaierTV();
    }

    public Refrigerator takeThings() {
        return new HaierRefrigerator();
    }
}
複製代碼
public class ChanghongFactory extends Factory {
    public TV watchTV() {
        return new ChanghongTV();
    }
    
    public Refrigerator takeThings() {
        return new ChanghongRefrigerator();
    }
}
複製代碼

3.4.7 客戶端調用

public class Test {

    public static void main(String[] args) throws Exception {
        Factory factory = new HaierFactory();
        TV tv = factory.watchTV();
        tv.openTV();
        Refrigerator refrigerator = factory.takeThings();
        refrigerator.openRefrigerator();
    }
}
複製代碼
3.5 適用場景
  • 一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部形態的工廠模式都是重要的。
  • 系統的產品有多於一個的產品族,而系統只消費羣體某一族的產品。
  • 同屬於同一產品族的產品是在一塊兒使用的,這一約束必須在系統的設計中體現出來。 *系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴與實現。
3.6 優缺點

3.6.1 優勢

  • 抽象工廠模式隔離了具體類的生成,使得客戶不須要知道什麼被建立。因爲這種隔離,更換一個具體工廠就變得相對容易。全部的具體工廠都實現了抽象工廠中定義的那些公共接口,所以只需改變具體工廠的實例,就能夠在某種程序上改變整個系統的行爲。另外,應用抽象工廠模式能夠實現高內聚低耦合的設計目的。
  • 當一個產品族中的多個對象被設計成一塊兒工做時,它可以保證客戶端始終只使用同一個產品族中的對象。這對一些須要根據當前環境來決定其行爲的軟件系統來講,是一種很是使用的設計模式。
  • 增長新的具體工廠和產品族很方便,無須改動其餘,符合「開閉」原則。

3.6.2 缺點

  • 在添加新的產品對象時,難以擴展抽象工廠來生產新種類的產品,這是由於在抽象工廠角色中規定了全部可能被場景的產品集合,要支持新種類的產品就意味着要對接口進行擴展,而這將涉及到對抽象工廠角色及其全部子類的修改,顯然帶來較大的不便。
  • 開閉原則的傾斜性(增長新的工廠和產品族容易,增長新的產品等級結構麻煩)。

特別聲明:一、如若文中有錯之處,歡迎大神指出。 二、文章是參考網上一些大神的文章,本身整理出來的,如如有侵權,可聯繫我刪除。

相關文章
相關標籤/搜索