1. 程式人生 > >通過例項說設計模式——簡單工廠模式

通過例項說設計模式——簡單工廠模式

本文我們通過例項的方式來簡單描述一下簡單工廠模式的由來及其作用,話說我們現在需要開發一個圖形介面工具,然後將這個工具提供給一個客戶去使用,系統初期我們只需要畫一個圓(Circle)和一個三角形(Triangle)即可。那麼我們的工具就按照如下的方式設計。

public class Shape {
    public void draw(String type) {
        if(type.equals("circle")) {
            System.out.println("畫一個圓");
        }else if(type.equals("triangle"
)) { System.out.println("畫一個三角形"); } } }

當客戶使用時就可以直接按照如下的方式去使用

public class TestDemo {
    public static void main(String[] args) {
        Shape shape = new Shape();
        shape.draw("circle");
        shape.draw("triangle");
    }
}

過一段時間之後,我們發現我們的工具中需要增加長方形(Rectangle)、正方形(Square)等很多其他的圖形。那麼這時我們就需要修改我們的Shape類。那麼我們的Shape類會變成如下的樣子。

public class Shape {
    public void draw(String type) {
        if(type.equals("circle")) {
            System.out.println("畫一個圓");
        }else if(type.equals("triangle")) {
            System.out.println("畫一個三角形");
        }else if(type.equals("...")){
//長方形
  }else if(type.equals("...")){
//正方形
} } }

那麼如果按照這樣的設計將會造成如下的一些缺陷。

  1. 我們的Shape類中的程式碼會因為圖形的不斷增多,會出現過多的if{}else{}程式碼塊,整個類的程式碼會非常的多,非常不容易閱讀。

  2. Shape類的職責過重,它負責初始化所有的圖形物件,將所有的圖形初始化程式碼放在一個類中,違反“單一職責(一個類或者一個方法只負責執行或完成一個任務)”原則,非常不利於重構及維護。

  3. 當需要增加新的圖形時,需要修改Shape的原始碼,違背“開閉原則(開:開放拓展;閉:不能修改原來的程式碼)”;

  4. 客戶在使用的時候,需要通過new關鍵字來直接建立Shape物件,Shape與客戶端的耦合度非常之高;

面對上面的一些缺陷呢,接下來我們慢慢開始一個一個的解決。

首先,對於圖形的不斷增多,會增加Shape類的程式碼量、同時不同的圖形,其繪製的方法不一樣,即職責不一樣;所以我們將不同的圖形放在不同的類中去實現。

public class Circle {
    public void draw() {
        System.out.println("繪製圓形");
    }
}
public class Triangle {
    public void draw() {
        System.out.println("繪製三角形");
    }
}
//.. ...

客戶端呼叫時按照如下方式去呼叫

public class TestDemo {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();

        Triangle triangle = new Triangle();
        triangle.draw();
    }
}

通過上面的改造我們發現,我們遵循了“單一職責原則”將圖形的實現劃分到了不同的圖形類中,但是這種實現中,客戶使用時需要知道所有的圖形類,並且需要通過new關鍵字來例項化具體的圖形,我們的工具中的具體實現類與客戶程式的耦合度非常的高。接下來我們再做一些改造,讓客戶的使用與具體的圖形實現類解耦。
首先我們宣告一個圖形(Shape)介面如下:

public interface Shape {
    /**
     * 繪製圖形
     */
    void draw();
    /**
     * 擦除圖形
     */
    void erase();
}

具體圖形類實現該介面,示例如下

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("繪製圓形");
    }

    @Override
    public void erase() {
        System.out.println("擦除圓形");
    }
}

public class Triangle implements Shape {

    @Override
    public void draw() {
        // TODO Auto-generated method stub
        System.out.println("繪製三角形");
    }

    @Override
    public void erase() {
        // TODO Auto-generated method stub
        System.out.println("擦除三角形");
    }
}

要讓客戶端與具體的實現類之間解耦,那麼我們就需要重新建立一個類,通過這個類來獲取具體的圖形例項,然後將圖形物件提供給客戶端使用即可,這個類我們就稱之為簡單工廠。

public class ShapeFactory {
    public static Shape getShape(String type) {
        if(type.equals("triangle")) {
            return new Triangle();
        }else if(type.equals("circle")) {
            return new Circle(10);
        } else {
            System.out.println("不支援的型別");
            return null;
        }
    }
}

客戶端在使用我們的工具時,不需要知道具體的圖形類實現,只需要知道我們提供的圖形工具中有一個工廠類ShapeFactory,並且通過一些固定的引數能夠獲取到想要的圖形即可。

public class TestDemo {
    public static void main(String[] args) {
        Shape shape = ShapeFactory.getShape("triangle");
        shape.draw();
        shape.erase();

        shape=ShapeFactory.getShape("circle");
        shape.draw();
        shape.erase();
    }
}

這樣我們就實現了一個簡單工廠,通過簡單工廠,我們實現了客戶端與具體實現類的解耦,同時具體類的實現也遵循了“單一職責原則”,同時提高了程式碼的可讀性、降低了程式碼的複雜度;

  • 簡單工廠模式的定義:定義一個工廠類, 它可以根據引數的不同返回不同類的例項, 被建立的例項通常都具有共同的父類或者實現了同一個介面。因為在簡單工廠模式中用於建立例項的方法是靜態(static)方法, 因此簡單工廠模式又被稱為靜態工廠方法(Static Factory Method)模式, 它屬於類建立型模式。

  • 簡單工廠模式的要點:當你需要什麼, 只需要傳入一個正確的引數, 就可以獲取你所需
    要的物件, 而無須知道其建立細節。

在簡單工廠模式結構圖中包含如下幾個角色

  • Factory( 工廠角色) : 工廠角色即工廠類(以上示例中的ShapeFactory), 它是簡單工廠模式的核心, 負責實現建立所有產品例項的內部邏輯; 工廠類可以被外界直接呼叫, 建立所需的產品物件; 在工廠類中提供了靜態的工廠方法factoryMethod(), 它的返回型別為具體實現型別的公共介面(上例中的Shape介面)或父類。

  • 具體型別的公共介面(Shape)或父類:他是工廠所建立的所有物件的父類,封裝了所有被建立物件的公共方法,該角色的引入大大提高了系統的靈活性,使得工廠類中只需要定義一個通用的工廠方法,因為所有建立的具體物件都是該角色的子類物件,為客戶端和具體實現類之間的解耦提供了很大的好處。

  • 具體實現類(如Circle、Triangle ):它是工廠類建立的目標,所有被建立的物件都充當這個角色的某個具體實現類。具體實現類都實現了一個公共的介面或者都繼承了一個公共的父類,它們需要實現介面或父類中宣告的抽象方法。

小結

簡單工廠模式提供了專門的工廠類用於建立物件, 將物件的建立和物件的使用分離開, 它作為一種最簡單的工廠模式在軟體開發中得到了較為廣泛的應用。

簡單工廠模式的優點

  • 工廠類包含一些邏輯判斷,可以決定在什麼時候建立哪一個具體類的例項。

  • 由於簡單工廠模式實現了物件的建立和使用分離,所以當增加具體類時,只需要在工廠類中增加對應的建立邏輯,不會影響客戶端對工具的使用。

  • 客戶端無需知道所建立的具體類,只需要知道具體的類所對應的引數即可,對於一些複雜的類名,通過簡單工廠模式可以在一定程度上減少使用者的記憶量。

簡單工廠模式的缺點

  • 具體類例項的建立都放在單一的工廠類中,工廠類的職責過重;

  • 當具體類變得越來越多時,工廠類的程式碼量會越來越龐大,不利於閱讀和維護;

  • 當增加新的具體類時,都需要修改工廠類將新的具體類的例項建立方式在工廠類中實現,不符合“開閉原則”;

  • 簡單工廠模式由於使用了靜態工廠方法, 造成工廠角色無法形成基於繼承的等級結構。

適用場景

  • 工廠類負責建立的物件比較少, 由於建立的物件較少, 不會造成工廠方法中的業務邏輯太過複雜。

  • 客戶端只知道傳入工廠類的引數, 對於如何建立物件並不關心。