設計模式(一):工廠模式

工廠方法模式(FACTORY METHOD)是一種常用的類創建型設計模式,此模式的核心精神是封裝類中變化的部分,提取其中個性化善變的部分爲獨立類,
通過依賴注入以達到解耦、複用和方便後期維護拓展的目的。它的核心結構有四個角色,分別是抽象工廠;具體工廠;抽象產品;具體產品

–摘自《百度百科》

前言

寫文章的目的主要是爲了自己知識的鞏固,當然也十分希望在此能夠得到業界前輩們的指導。

本篇文章圍繞:簡單工廠模式、工廠方法模式、抽象工廠模式來大致說明。


設計模式的使用是爲了提高代碼質量、優雅度以及後期更好的重構項目,如果只是爲了實現功能而去編寫代碼就完全沒有這個必要了。當然它的缺點會降低一部分可讀性。


場景:某汽車工廠->根據不同訂單->生產不同品牌的汽車

1.簡單工廠模式(Simple Factory Pattern)

定義:由\color{#FF0000}{一個工廠對象}決定創建出哪一種產品類的實例。

使用場景:簡單工廠模式適用於工廠類對象較少的場景,根據提供的工廠參數來生成不同的產品。無需關心生成過程(new 一個對象的必要條件)

準備工作

//定義一個規範
public interface ICar {
    //生產汽車
    public  void create();
}
//創建一個Audi實現ICar
public class Audi implements ICar {
    @Override
    public void create() {System.out.println("製造Audi");}
}
//創建一個BMW實現ICar
public class BMW implements ICar {
    @Override
    public void create() {System.out.println("製造BMW");}
}

以上代碼我們在平時開發中也會經常用到,把公共方法單獨抽象出一個類,如果按照我們以往的方法就是

 public static void main(String[] args) {
 	//需要一個Audi
    ICar icar = new Audi();
    icar.create();
    //在需要一個BMW
    ICar icar1 = new BMW();
    icar1.create();
    //這樣我們每需要一種汽車,我們都需要去單獨創建一個對象.如果品種越來越多,
    //代碼就會變的十分臃腫
 }

下面我們使用工廠模式對代碼進行優化

1.1 通過類名創建對象
public class CarFactory {
    //通過類名創建對象
    public ICar create(String name){
        if("Audi".equals(name)){
            return  new Audi();
        }else if("BMW".equals(name)){
            return new BMW();
        }else{//在實際中不建議使用null作爲返回值,會造成空指針不必要的麻煩.
            return null; 
        }
    }
}
 public static void main(String[] args) {
 	//調用
 	CarFactory factory = new CarFactory();//創建一個工廠對象
 	//需要一個Audi
 	ICar audi = factory.create("Audi");
 	//需要一個BMW
 	ICar bmw = factory.create("BMW");
 	
 	//此類方法根據傳入的類名來創建實例,對書寫要求較高不允許出現錯誤。顯然不合適
 	
 }
1.2通過包名創建對象
public class CarFactory {
    //通過類名創建對象
    public ICar create(String name){
       try {
            if(!(null == className ||"".equals(className))){
                //通過反射得到類的實例
                return (ICar)Class.forName(className).newInstance();
            }
        }catch (Exception e){
        }
        return null;
    }
}
 public static void main(String[] args) {
 	CarFactory factory = new CarFactory();//創建一個工廠對象
    ICar  bmw = factory.create("com.xx.BMW")
    //此方法通過反射來進行創建,雖然能在一定程度在降低錯誤,因爲我們複製全包名
    //的時候往往不會手動輸入(- -! 強行解釋一波),顯然不能解決我們的問題 繼續
 }
1.3 通過類對象創建實例
public class CarFactory {
    //通過類名創建對象
    public ICar create(Class cls){
       try {
            if(cls != null){
                //通過反射得到類的實例
                return cls.newInstance();
            }
        }catch (Exception e){
        }
        return null;
    }
}
public static void main(String[] args) {
 	CarFactory factory = new CarFactory();//創建一個工廠對象
    ICar  bmw = factory.create(BMW.class)
    //你是不是也覺得這樣錯誤率也就大大降低了。
    //相較於原始方法是不是在質量上有那麼一丟丟提高
 }

在這裏插入圖片描述
簡單工廠模式

優點:只需傳入一個正確合理的參數,就可以獲取你所需要的對象 無須知道其創建的過程。

缺點:都由工廠統一創建,工廠類的壓力較重,增加新的產品時需要修改工廠類的判斷 邏輯,違背開閉原則,不易於擴展相對複雜的結構。

2.工廠方法模式(Factory Method Pattern)

定義:定義一個接口,讓實現此接口的類來選擇創建哪個類。該工廠不做生產操作,把操作轉交給子工廠相當於代理工廠(打個比方:比如富士康幫助蘋果生產手機,而蘋果本身不生產手機。- - ! 這個比方請不要擡槓)

public interface CarFactory {
    //總工廠,將創建邏輯分給代理工廠一對一創建
    ICar create();
}
//代理工廠1:生產BMW
public class BMWFactory implements CarFactory{
    @Override
    public ICar create() {
        return new BMW();
    }
}
//代理工廠2:生產Audi
public class AudiFactory implements CarFactory{
    @Override
    public ICar create() {
        return new Audi();
    }
}
 public static void main(String[] args) {
        //去Audi工廠要Audi
        CarFactory factory = new AudiFactory();
        ICar audi = factory.create();
        //去BMW工廠要BMW
        factory = new BMWFactory();
        ICar bmw = factory.create();
    }

對工廠方法可以做一些改進:
將CarFactory定義一個抽象類,好處是能添加一些公共的創建條件.

//對工廠方法改進 定義爲一個抽象類
public abstract class CarFactory {
    //每個方法創建前的邏輯
    public void preCreate(){

    }

   //公共的方法定義成抽象方法
   abstract ICourse create();
}

在這裏插入圖片描述
工廠方法模式:
優點:適用於創建對象時需要大量重複的代碼
缺點:類的個數較多,複雜度增加,相比第一種抽象了些增加了理解難度。

三、抽象工廠模式(Abastract Factory Pattern)

定義:提供一個創建一系列相關或相互依賴對象的接口,無須指定他們具體的類。
什麼意思呢?這裏解釋一下,比方:
1.某一總工廠不單單生產汽車,可能還會生產手機,洗衣機,冰箱等一系列產品。
2.A代理工廠會生產汽車、手機、冰箱、洗衣機。(A生產的產品屬於一系列產品 A品牌)
3.B代理工廠會生產汽車、手機、洗衣機。(B生產的產品屬於一系列產品 B品牌)
\color{#FF0000}{總工廠就相當於一個產品類的庫,所有的產品對象都從同一個接口出現,}
使\color{#FF0000}{從而使 客戶端方面不依賴與具體實現}
下面請看例子:

//所有的工廠都實現這個工廠,一個品牌的抽象
public interface IFactory {
    //製造汽車
    ICar Car();
    //製造電腦
    IComputer computer();
}

//A工廠實現
public class AFactory implements IFactory{
    @Override
    public ICar Car() {
        return new Audi();
    }
    @Override
    public IComputer computer() {
        return new DellComputer();
    }
}
//B工廠實現
public class BFactory implements  IFactory{
    @Override
    public ICar Car() {
        return new Audi();
    }
    @Override
    public IComputer computer() {
        return new DellComputer();
    }
}
   public static void main(String[] args) {
        //A工廠 生產A品牌的一系列
        IFactory factory = new AFactory();
        factory.Car();
        factory.computer();
        //B工廠 生產B品牌的一系列
        IFactory factory1 = new BFactory();
        factory1.computer();
        factory1.Car();
    }

抽象類工廠模式:
優點:擴展性非常強、具體產品在應用層代碼隔離,無須關心創建細節、將一個系列的產品統一到一起創建。在spring框架中應該非常廣泛
缺點:不符合開閉原則、如果此工廠增加了一個產品,那麼所有的子工廠都要實現此方法。
試想一下如果IFactory增加了一個產品,A和B以及更多的子工廠都要實現此類方法。


對本文中\color{#FF0000}{開閉原則}的補充:
定義:是指一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。所謂的開閉,也正是對擴展和修改兩個行爲的一個原則。強調的是用抽象構建框架,用實現擴展細節。可以提高軟件系統的可複用性及可維護性。開閉原則,是面向對象設計中最基礎的設計原則。它指導我們如何建立穩定靈活的系統,例如:我們版本更新,我儘可能不修改源代碼,但是可以增加新功能。請看案例

public class Car {
    private String name;
    private Double price;
    private String color;

    public Car(String name, Double price, String color) {
        this.name = name;
        this.price = price;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

定義一個汽車,某一天商場做活動,對汽車打折扣如果我們直接修改getPrice()或setPrice()方法會存在一定的風險,可能會影響到其他地方的調用結果。那麼該如何處理?
----另外編寫一個類處理此邏輯

public class CarPrice extends Car{

    public CarPrice(String name, Double price, String color) {
        super(name, price, color);
    }

    public Double OriginPrice(){
        return super.getPrice();
    }

    public Double getPrice(){
        return super.getPrice()*0.5;
    }
}

以上三種方式都有適合自己的場景,沒有好壞之分,具體根據實際情況選擇。

希望各位看過的夥伴們如果發現了問題能夠及時批評指正,在此感謝。

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