設計模式-簡單工廠模式

模式定義

簡單工廠模式是屬於建立型模式,又叫作靜態工廠方法(Static Factory Method)模式,但不屬於23種GOF設計模式之一。簡單工廠模式定義了一個建立對象的類,由這個類來封裝實例化對象的行爲。java

設計原則

遵循的原則:編程

  • 依賴倒置原則
  • 迪米特法則
  • 里氏替換原則
  • 接口隔離原則

未遵循的原則設計模式

  • 開閉原則
  • 單一職責原則

UML類圖

簡單工廠模式類圖

簡單工廠模式實例

問題描述ide

Pizza 類有不少子類,要求根據不一樣的狀況用不一樣的子類實例化一個 Pizza 對象。工具

首先咱們定義披薩接口測試

package com.wpx.simplefactory;

/**
 * 定義披薩接口
 */
public interface Pizza {
    public void make();
}

接着,定義兩個具體的披薩類,乳酪比薩和希臘披薩設計

package com.wpx.simplefactory;

/**
 * 具體的披薩-乳酪比薩
 */
public class CheesePizza implements Pizza {

    @Override
    public void make() {
        System.out.println("乳酪比薩");
    }
}
package com.wpx.simplefactory;

/**
 * 具體的披薩-希臘披薩
 */
public class GreekPizza implements Pizza {

    @Override
    public void make() {
        System.out.println("希臘披薩");

    }
}

緊接着,咱們定義一個披薩工廠來生產披薩code

package com.wpx.simplefactory;

/**
 * 披薩工廠類
 */
public class SimplePizzaFactory {
    public static Pizza createPizza(String type) {
        if (type.equals("乳酪比薩")) {
            return new CheesePizza();
        } else if (type.equals("希臘披薩")) {
            return new GreekPizza();
        } else {
            throw new UnsupportedOperationException();
        }
    }
}

如今一個基於簡單工廠模式的披薩工廠就建造完成了,咱們對此進行測試,讓披薩工廠來一份乳酪披薩嚐嚐。orm

package com.wpx.simplefactory;

/**
 * 測試簡單工廠模式-披薩工廠
 */
public class PizzaStore {
    public static void main(String[] args) {
        Pizza pizza = SimplePizzaFactory.createPizza("乳酪比薩");
        pizza.make();
    }
}

運行結果對象

乳酪比薩

Process finished with exit code 0

java.text.DateFormat中的簡單工廠模式

DateFormat:jdk中的一個工具類java.text.DateFormat,用來格式化一個本地日期與時間

經過源碼咱們能夠知道DateFormat是一個抽象類(abstract),下面的源代碼就是這個類裏包含的方法,其實這些就是靜態工廠方法,經過靜態方法來提供本身的實例是徹底能夠的(抽象類自己不能進行實例化)。從源碼能夠看出getDateInstance()方法作了兩件事情:

  1. 運用了多態性:因爲SimpleDateFormat是DateFormat的子類,而getDateInstance()聲明的類型爲DateFormat而實際返回類型爲子類SimpleDateFormat
  2. 使用了靜態工廠方法(static):因爲DateFormat是抽象類不能進行實例化,所以也就不能調用其中的普通方法(非靜態方法)。所以咱們必須將其聲明爲static,才能返回實例

經過上面作的兩件事情就將具體子類的實例化過程隱藏起來了,調用者沒必要考慮具體子類的實例化,由於抽象類會提供它的合適子類實例

public final static DateFormat getDateInstance()
    {
        return get(0, DEFAULT, 2, Locale.getDefault());
    }

    public final static DateFormat getDateInstance(int style)
    {
        return get(0, style, 2, Locale.getDefault());
    }

    public final static DateFormat getDateInstance(int style,
                                                 Locale aLocale)
    {
        return get(0, style, 2, aLocale);
    }
    
    private static DateFormat get(int timeStyle, int dateStyle,
                                  int flags, Locale loc) {
        if ((flags & 1) != 0) {
            if (timeStyle < 0 || timeStyle > 3) {
                throw new IllegalArgumentException("Illegal time style " + timeStyle);
            }
        } else {
            timeStyle = -1;
        }
        if ((flags & 2) != 0) {
            if (dateStyle < 0 || dateStyle > 3) {
                throw new IllegalArgumentException("Illegal date style " + dateStyle);
            }
        } else {
            dateStyle = -1;
        }
        try {
            // Check whether a provider can provide an implementation that's closer 
            // to the requested locale than what the Java runtime itself can provide.
            LocaleServiceProviderPool pool =
                LocaleServiceProviderPool.getPool(DateFormatProvider.class);
            if (pool.hasProviders()) {
                DateFormat providersInstance = pool.getLocalizedObject(
                                                    DateFormatGetter.INSTANCE,
                                                    loc, 
                                                    timeStyle,
                                                    dateStyle,
                                                    flags);
                if (providersInstance != null) {
                    return providersInstance;
                }
            }

            return new SimpleDateFormat(timeStyle, dateStyle, loc);
        } catch (MissingResourceException e) {
            return new SimpleDateFormat("M/d/yy h:mm a");
        }
    }

總結

優勢:

  • 將建立實例的工做與使用實例的工做分開,使用者沒必要關心類對象如何建立,明確了職責。
  • 把初始化實例時的工做放到工廠裏進行,使代碼更容易維護。更符合面向對象的原則,面向接口編程,而不是面向實現編程。

缺點:

  • 因爲工廠類集中了全部產品建立邏輯,一旦不能正常工做,整個系統都要受到影響。
  • 要新增產品類的時候,就要修改工廠類的代碼,違反了開放封閉原則(對擴展的開放,對修改的關閉)。
  • 簡單工廠模式因爲使用了靜態工廠方法,形成工廠角色沒法造成基於繼承的等級結構。
相關文章
相關標籤/搜索