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

設計模式學習

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

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

設計模式的類型

下面這是從菜鳥教程上面摘的,感覺不錯就拿下來了,http://www.runoob.com/design-pattern/design-pattern-intro.html

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

       這些設計模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用 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 廠商是個父類,有生產鼠標,生產鍵盤兩個接口。

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

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

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

/**
 * @ClassName: Mouse
 * @Description: Mouse接口類
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:36
 */
public interface Mouse {
    public void sayHi();
}
/**
 * @ClassName: DellMouse
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:39
 */
public class DellMouse implements Mouse{
    public void sayHi(){
        System.out.println("produce DellMouse");
    }
}
/**
 * @ClassName: HpMouse
 * @Description: mouse接口實體類
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:40
 */
public class HpMouse implements Mouse{
    public void sayHi(){
        System.out.println("produce HpMouse");
    }
}
/**
 * @ClassName: Keybo
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:42
 */
public interface Keybo {
    public void sayHi();
}
/**
 * @ClassName: DellKeybo
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:43
 */
public class DellKeybo implements Keybo{
    public void sayHi(){
        System.out.println("produce DellKeybo");
    }
}
/**
 * @ClassName: HpKeybo
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:44
 */
public class HpKeybo implements Keybo{
    public void sayHi(){
        System.out.println("produce HpKeybo");
    }
}
/**
 * @ClassName: PcFactory
 * @Description: 工廠類接口
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:45
 */
public interface PcFactory {
    public Mouse createMouse();
    public Keybo createKeybo();
}
/**
 * @ClassName: DellFactory
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:46
 */
public class DellFactory implements PcFactory{
    @Override
    public Mouse createMouse() {
        return new DellMouse();
    }

    @Override
    public Keybo createKeybo() {
        return new DellKeybo();
    }
}
/**
 * @ClassName: HpFactory
 * @Description: java類作用描述
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:48
 */
public class HpFactory implements PcFactory{
    @Override
    public Mouse createMouse() {
        return new HpMouse();
    }

    @Override
    public Keybo createKeybo() {
        return new HpKeybo();
    }
}
/**
 * @ClassName: AbstractFactoryPatternTest1
 * @Description: 測試類
 * @Author: xinyuan
 * @CreateDate: 2018/9/24 9:50
 */
public class AbstractFactoryPatternTest1 {
    public static void main(String[] args){
        PcFactory pcFactory = new DellFactory();
        Keybo keybo = pcFactory.createKeybo();
        keybo.sayHi();
        Mouse mouse = pcFactory.createMouse();
        mouse.sayHi();

        PcFactory pcFactory1 = new HpFactory();
        Keybo keybo1 = pcFactory1.createKeybo();
        keybo1.sayHi();
        Mouse mouse1 = pcFactory1.createMouse();
        mouse1.sayHi();
    }
}

 

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

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

之後創建華碩鼠標,繼承鼠標類。創建華碩鍵盤,繼承鍵盤類即可。

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

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

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章