1. 程式人生 > >設計模式學習總結(1)簡單工廠模式、工廠方法模式、抽象工廠模式

設計模式學習總結(1)簡單工廠模式、工廠方法模式、抽象工廠模式

設計模式學習

做了幾個專案,發現設計模式的好處還是很多的,這東西就是隻有你真正用到的時候才知道他的好處,否則學了也不知道所以然。所以設計模式學習我認為可以在先進行幾個專案後,再來學習,這樣學習的效果和感受才是最好的。

這次是做一個學習的筆記,內容還是主要以我看的兩本書《大話設計模式》、《head first 設計模式》,以及我在網上找到的一些內容為主,還有就是附帶的一些自己的感悟(這些有可能是有問題的,還會再改,所以大家要是看一定要有分辨地去看)。主要還是覺得做一個學習的筆記可能會是我堅持下去的動力。

設計模式的型別

建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。

       這些設計模式提供了一種在建立物件的同時隱藏建立邏輯的方式,而不是使用 new 運算子直接例項化物件。這使得程式在判斷針對某個給定例項需要建立哪些物件時更加靈活。

結構型模式,共七種:介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

       這些設計模式關注類和物件的組合。繼承的概念被用來組合介面和定義組合物件獲得新功能的方式。

行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。

      這些設計模式特別關注物件之間的通訊。

下面是設計模式的一張關係圖

設計模式的六大原則

1、開閉原則(Open Close Principle)

開閉原則的意思是:對擴充套件開放,對修改關閉。在程式需要進行拓展的時候,不能去修改原有的程式碼,實現一個熱插拔的效果。簡言之,是為了使程式的擴充套件性好,易於維護和升級。想要達到這樣的效果,我們需要使用介面和抽象類,後面的具體設計中我們會提到這點。

2、里氏代換原則(Liskov Substitution Principle)

里氏代換原則是面向物件設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。LSP 是繼承複用的基石,只有當派生類可以替換掉基類,且軟體單位的功能不受到影響時,基類才能真正被複用,而派生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關係就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規範。

3、依賴倒轉原則(Dependence Inversion Principle)

這個原則是開閉原則的基礎,具體內容:針對介面程式設計,依賴於抽象而不依賴於具體。

4、介面隔離原則(Interface Segregation Principle)

這個原則的意思是:使用多個隔離的介面,比使用單個介面要好。它還有另外一個意思是:降低類之間的耦合度。由此可見,其實設計模式就是從大型軟體架構出發、便於升級和維護的軟體設計思想,它強調降低依賴,降低耦合。

5、迪米特法則,又稱最少知道原則(Demeter Principle)

最少知道原則是指:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模組相對獨立。

6、合成複用原則(Composite Reuse Principle)

合成複用原則是指:儘量使用合成/聚合的方式,而不是使用繼承。

1、工廠模式

簡單工廠模式(simple Factory)

簡單工廠模式不屬於23種設計模式中的一種,簡單工廠一般分為:普通簡單工廠、多方法簡單工廠、靜態方法簡單工廠。就是有一個專門生產某個產品的類

在簡單工廠模式中,一個工廠類處於對產品類例項化呼叫的中心位置上,它決定那一個產品類應當被例項化, 如同一個交通警察站在來往的車輛流中,決定放行那一個方向的車輛向那一個方向流動一樣。

01普通

介面shape類


/**
 * 簡單工廠模式
 * 建立一個介面
 * shape類:實現介面
 */
public interface shape {
    void draw();
}

介面實現實體類:Circle類、Rectangle

public class Circle implements shape{
    @Override
    public void draw(){
        System.out.println("draw a circle");
    }
}
/**
 * 簡單工廠模式
 * 建立一個實現介面的實體類
 * Rectangle畫一個矩形
 */
public class Rectangle implements shape{
    @Override
    public void draw(){
        System.out.println("draw a Rectangle");
    }
}

 工廠類

/**
 * 簡單工廠模式
 * 建立一個工廠,生成基於給定資訊的實體類的物件
 * 2018/9/23  15:40
 */
public class ShapeFactory {
    //使用一個getShape方法獲取形狀型別物件
    public shape getShape(String shapeType){
        if(shapeType == null){
            System.out.println("please enter right word:");
        }else if(shapeType.equals("circle")){
            return new Circle();
        }else if(shapeType.equals("rectangle")){
            return new Rectangle();
        }
        return null;
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: SimpleFactoryPatternTest
 * @Description: 簡單工廠模式,用於進行測試
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 15:48
 */
public class SimpleFactoryPatternTest {
    public static void main(String[] args){
        ShapeFactory shapeFactory = new ShapeFactory();
        //獲取Circle物件,並呼叫它的draw方法
        shape shape1 = shapeFactory.getShape("circle");
        shape1.draw();

        //獲取Rectangle物件,並呼叫它的draw方法
        shape shape2 = shapeFactory.getShape("rectangle");
        shape2.draw();

    }
}

測試結果: 

draw a circle
draw a Rectangle

Process finished with exit code 0

02多個方法

工廠類和測試類發生改變,其餘不變

/**
 * @ProjectName: Factory_Pattern
 * @ClassName: ShapeFactory1
 * @Description: 多個方法的簡單工廠模式的工廠類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:06
 */
public class ShapeFactory1 {
    public shape drawCircle(){
        return new Circle();
    }

    public shape drawRectangle(){
        return new Rectangle();
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: SimpleFactoryPatternTest1
 * @Description: 多個方法的簡單工廠模式,用於進行測試
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:10
 */
public class SimpleFactoryPatternTest1 {
    public static void main(String[] args){
        ShapeFactory1 shapeFactory1 = new ShapeFactory1();
        //獲取Circle物件,並呼叫它的draw方法
        shape shape1 = shapeFactory1.drawCircle();
        shape1.draw();

        //獲取Rectangle物件,並呼叫它的draw方法
        shape shape2 = shapeFactory1.drawRectangle();
        shape2.draw();
    }
}

測試結果同上,就不放了。。。

03 多個靜態方法

將工廠裡的方法設定為靜態的,這樣在main裡就可以不建立實體直接呼叫。

/**
 * @ProjectName: Factory_Pattern
 * @ClassName: ShapeFactory2
 * @Description: 多個靜態方法的簡單工廠模式的工廠類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:17
 */
public class ShapeFactory2 {
    public static shape drawCircle(){
        return new Circle();
    }

    public static shape drawRectangle(){
        return new Rectangle();
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: SimpleFactoryPatternTest2
 * @Description: 多個靜態方法的簡單工廠模式的測試類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:19
 */
public class SimpleFactoryPatternTest2 {
    public static void main(String[] args){
        shape circle = ShapeFactory2.drawCircle();
        circle.draw();

        shape rectangle = ShapeFactory2.drawRectangle();
        rectangle.draw();
    }
}

測試結果同上。。。

2、工廠方法模式(Factory Method)

簡單工廠模式有一個問題就是,類的建立依賴工廠類,也就是說,如果想要拓展程式,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到工廠方法模式,建立一個工廠介面和建立多個工廠實現類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的程式碼。(給工廠也建立一個相應的介面,這樣就好拓展了)

/**
 * @ProjectName: Factory_Pattern
 * @ClassName: ShapeFactory
 * @Description: 工廠類的介面
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:43
 */
public interface ShapeFactory {
    public shape drawShape();
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: DrawCircleFactory
 * @Description: 工廠方法模式,工廠實體類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:45
 */
public class DrawCircleFactory implements ShapeFactory{
    @Override
    public shape drawShape(){
        return new Circle();
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: DrawRectangleFactory
 * @Description: 工廠方法模式,工廠實體類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:46
 */
public class DrawRectangleFactory implements ShapeFactory{
    public shape drawShape(){
        return new Rectangle();
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: FactoryPatternTest
 * @Description: 工廠方法模式測試類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:47
 */
public class FactoryPatternTest {
    public static void main(String[] args){
        ShapeFactory shapeFactory = new DrawCircleFactory();
        shape circle = shapeFactory.drawShape();
        circle.draw();

        ShapeFactory shapeFactory1 = new DrawRectangleFactory();
        shape rectangle = shapeFactory1.drawShape();
        rectangle.draw();
    }
}

3、抽象工廠方法

工廠方法模式:
一個抽象產品類,可以派生出多個具體產品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類只能建立一個具體產品類的例項。

抽象工廠模式:
多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類可以建立多個具體產品類的例項,也就是建立的是一個產品線下的多個產品。   
    
區別:
工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。   
工廠方法模式的具體工廠類只能建立一個具體產品類的例項,而抽象工廠模式可以建立多個。
工廠方法建立 "一種" 產品,他的著重點在於"怎麼建立",也就是說如果你開發,你的大量程式碼很可能圍繞著這種產品的構造,初始化這些細節上面。也因為如此,類似的產品之間有很多可以複用的特徵,所以會和模版方法相隨。 

抽象工廠需要建立一些列產品,著重點在於"建立哪些"產品上,也就是說,如果你開發,你的主要任務是劃分不同差異的產品線,並且儘量保持每條產品線介面一致,從而可以從同一個抽象工廠繼承。
對於java來說,你能見到的大部分抽象工廠模式都是這樣的:
---它的裡面是一堆工廠方法,每個工廠方法返回某種型別的物件。

比如說工廠可以生產滑鼠和鍵盤。那麼抽象工廠的實現類(它的某個具體子類)的物件都可以生產滑鼠和鍵盤,但可能工廠A生產的是羅技的鍵盤和滑鼠,工廠B是微軟的。

這樣A和B就是工廠,對應於抽象工廠;
每個工廠生產的滑鼠和鍵盤就是產品,對應於工廠方法;

用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從羅技換到微軟。但是用了抽象工廠模式,你只要換家工廠,就可以同時替換滑鼠和鍵盤一套。如果你要的產品有幾十個,當然用抽象工廠模式一次替換全部最方便(這個工廠會替你用相應的工廠方法)

所以說抽象工廠就像工廠,而工廠方法則像是工廠的一種產品生產線
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: Color
 * @Description: 抽象工廠模式
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 17:17
 */
public interface Color {
    public void fill();
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: Red
 * @Description: 抽象工廠模式,color介面的實體類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 17:18
 */
public class Red implements Color{
    @Override
    public void fill(){
        System.out.println("color is red");
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: Blue
 * @Description: 抽象工廠模式,color介面的實體類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 17:20
 */
public class Blue implements Color{
    public void fill(){
        System.out.println("color is blue");
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: DrawBlueFactory
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 17:30
 */
public class DrawBlueFactory implements ShapeFactory{
    @Override
    public shape drawShape(){
        return null;
    }

    @Override
    public Color drawColor(){
        return new Blue();
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: DrawRedFactory
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 17:25
 */
public class DrawRedFactory implements ShapeFactory{
    @Override
    public shape drawShape(){
        return null;
    }

    @Override
    public Color drawColor(){
        return new Red();
    }
}
/**
 * @ProjectName: Factory_Pattern
 * @ClassName: FactoryPatternTest
 * @Description: 工廠方法模式測試類
 * @Author: xinyuan
 * @CreateDate: 2018/9/23 16:47
 */
public class FactoryPatternTest {
    public static void main(String[] args){
        ShapeFactory shapeFactory = new DrawCircleFactory();
        shape circle = shapeFactory.drawShape();
        circle.draw();

        ShapeFactory shapeFactory1 = new DrawRectangleFactory();
        shape rectangle = shapeFactory1.drawShape();
        rectangle.draw();

        ShapeFactory shapeFactory2 = new DrawRedFactory();
        Color red = shapeFactory2.drawColor();
        red.fill();

        ShapeFactory shapeFactory3 = new DrawBlueFactory();
        Color blue = shapeFactory3.drawColor();
        blue.fill();
    }
}

下面的這些是從菜鳥教程上找的,感覺總結的挺好的,就拿下來看看,這樣也好以後複習。

下面例子中滑鼠,鍵盤,耳麥為產品,惠普,戴爾為工廠。

簡單工廠模式

簡單工廠模式不是 23 種裡的一種,簡而言之,就是有一個專門生產某個產品的類。

比如下圖中的滑鼠工廠,專業生產滑鼠,給引數 0,生產戴爾滑鼠,給引數 1,生產惠普滑鼠。

工廠模式

工廠模式也就是滑鼠工廠是個父類,有生產滑鼠這個介面。

戴爾滑鼠工廠,惠普滑鼠工廠繼承它,可以分別生產戴爾滑鼠,惠普滑鼠。

生產哪種滑鼠不再由引數決定,而是建立滑鼠工廠時,由戴爾滑鼠工廠建立。

後續直接呼叫滑鼠工廠.生產滑鼠()即可

抽象工廠模式

抽象工廠模式也就是不僅生產滑鼠,同時生產鍵盤。

也就是 PC 廠商是個父類,有生產滑鼠,生產鍵盤兩個介面。

戴爾工廠,惠普工廠繼承它,可以分別生產戴爾滑鼠+戴爾鍵盤,和惠普滑鼠+惠普鍵盤。

建立工廠時,由戴爾工廠建立。

後續工廠.生產滑鼠()則生產戴爾滑鼠,工廠.生產鍵盤()則生產戴爾鍵盤。

在抽象工廠模式中,假設我們需要增加一個工廠

假設我們增加華碩工廠,則我們需要增加華碩工廠,和戴爾工廠一樣,繼承 PC 廠商。

之後建立華碩滑鼠,繼承滑鼠類。建立華碩鍵盤,繼承鍵盤類即可。

在抽象工廠模式中,假設我們需要增加一個產品

假設我們增加耳麥這個產品,則首先我們需要增加耳麥這個父類,再加上戴爾耳麥,惠普耳麥這兩個子類。

之後在PC廠商這個父類中,增加生產耳麥的介面。最後在戴爾工廠,惠普工廠這兩個類中,分別實現生產戴爾耳麥,惠普耳麥的功能。 以上。