26設計模式之工廠模式

工廠模式用來解決具有相同特徵類的創建問題,分爲3中類型:簡單工廠模式、工廠方法模式、抽象工廠模式,其中可以把簡單工廠模式看做是工廠方法模式的一種特殊情況,抽象工廠模式是在工廠方法下的進一步抽象。

簡單工廠模式:

1、工廠類角色,用來創建具體產品。

2、抽象產品類,是具體產品類的父類。

3、具體產品類,最終需要生產的對象。

工廠方法模式:

1、抽象工廠,是具體工廠類的父類,用來規範生產。

2、具體工廠,實際的生產工廠類。

3、抽象產品,同上。

4、具體產品,同上。

抽象工廠模式:

1、抽象工廠,同上

2、具體工廠,同上

3、抽象產品,同上。

4、具體產品,同上。

下面就以以前的生產手機爲例演示各種模式的使用方式,首先我們使用簡單工廠模式。我們知道手機有不同的品牌和配置,可這我們也可以把它看做共同點,因爲他們都有這些屬性,所以我們把它抽象爲一個抽象產品類Phone,代碼如下:

public abstract class Phone {
    String brand, cup;
    abstract void call();
    abstract void sendMSG();
}
現在我們需要生產兩種手機,一種是蘋果6s一種爲三星note5,他們是具體的產品,需要實現抽象的產品類,代碼如下

public class Iphone extends Phone {
    @Override
    void call() {
        Log.e("", "我使用:" + brand + "撥打的電話!它的cup爲:" + cup);
    }
    @Override
    void sendMSG() {
        Log.e("", "我使用:" + brand + "發送的短信!它的cup爲:" + cup);
    }
}
public class SumPhone extends Phone {
    @Override
    void call() {
        Log.e("", "我使用:" + brand + "撥打的電話!它的cup爲:" + cup);
    }
    @Override
    void sendMSG() {
        Log.e("", "我使用:" + brand + "發送的短信!它的cup爲:" + cup);
    }
}
有了產品後我們還需要一個生產產品的工廠,下面爲工廠類

public class PhoneFactory {
    public static Phone productPhone(String brand) {
        switch (brand) {
            case "蘋果":
                Iphone iphone = new Iphone();
                iphone.brand="蘋果6s";
                iphone.cup="A9";
                return iphone;
            case "三星":
                SumPhone sumPhone = new SumPhone();
                sumPhone.brand="三星note5";
                sumPhone.cup="Exynos7420";
                return sumPhone;
            default:
                return null;
        }
    }
}


ok,有了這些之後,我們就可以生產手機,我們只需要告訴工廠我們生產什麼牌子的手機,具體怎麼去生產是工廠的事我們不需要過多的關注,下面來看Activity裏面的代碼:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void start(View view) {
        Phone phone = PhoneFactory.productPhone("蘋果");
        phone.call();
        phone.sendMSG();
    }
}

佈局文件就一個按鈕,點擊按鈕執行start方法,下面看輸出日誌:



ok,因爲現在只需要生產兩種手機,工廠中的代碼不是很多,如果我們要生產多中手機,比如有華爲、魅族、小米、大米、黑米等等,一個工廠不可能都會生產所有的手機,即使能生產我們的工廠類也會變得非常的大,不利於我們的修改,既然工廠類只有一個一個product方法用來生產手機,那麼我們是不是可以把它抽象出來,作爲一個單獨的抽象工程類呢?這就形成了工廠方法模式,下面我們在以上的基礎上面新建一個ABSFactory類,代碼如下:

public abstract class ABSFactory {
   public  abstract Phone product(String brand);
}
然後我們有兩個工廠來生產手機,每個工廠能生產的手機不同,FactoryA的代碼如下:

public class FactoryA extends ABSFactory {

   public Phone product(String brand) {
       switch (brand) {
           case "黑米":
               MIPhone miPhone = new MIPhone();
               miPhone.brand="黑米10s";
               miPhone.cup="驍龍820";
               return miPhone;
           case "三星":
               SumPhone sumPhone = new SumPhone();
               sumPhone.brand="三星note5";
               sumPhone.cup="Exynos7420";
               return sumPhone;
           default:
               return null;
       }
    }
}


FactoryB的代碼如下:

public class FactoryB extends ABSFactory {
    @Override
    public Phone product(String brand) {
        switch (brand) {
            case "蘋果":
                Iphone iphone = new Iphone();
                iphone.brand = "蘋果6S";
                iphone.cup = "A9";
                return iphone;
            case "華爲":
                HuaWei huaWei = new HuaWei();
                huaWei.brand = "華爲鍋蓋手機";
                huaWei.cup = "海思119";
                return huaWei;
            default:
                return null;
        }
    }
}
兩個手機的代碼和先前的手機類類似就不貼出來了,下面我們需要生產一個黑米手機,我們只需要在Activity裏面把start方法代碼改爲:

 public void start(View view) {
        FactoryA factoryA = new FactoryA();
        Phone phone = factoryA.product("黑米");
        phone.call();
        phone.sendMSG();
    }

然後運行看結果:



這裏我們就看出來使用工廠模式的好處了吧,我們都沒有修改已有的產品類代碼,只需要添加新的代碼就可以了,而抽象方法的出現,如果在我們需要創建新的手機,而現有的A、B工廠無法生產的時候我們只需要創建一個C工廠就可以搞定了,代碼的耦合性是不是變低了呢?那麼現在問題來了,工廠如果只會生產手機,勢必沒有什麼競爭,壓力超大吶,你像前不久給錘子代工的工廠就掛了,所以工廠老闆說了:“同志們!現在光要你們加班是掙不到錢了,我們要做大做強必須要擴展我們的業務,從下週開始我們新開一個生產線用來生產路由器,以後加完班的如果還想加班可以來這條流水線上面加班!”,OMG,雖然廣東的小妹妹年輕,也不可以這麼蹂躪嘛,老總的一句話工人又要少活好幾年了~~~~~~~~~~~也因爲老總的這句話,出現一個新的工廠模式:抽象工廠模式,這個模式與工廠方法是極其相似的,只是抽象工程模式可以一次生產好幾種對象出來,而工廠方法模式只能生產一種對象,這就是他們最大的不同點,我們來看看ABSFactoryPlus類,他就是超級工程:

public abstract class ABSFactoryPlus {
    public  abstract Phone product(String brand);
    public abstract Router newProduct(String brand);
}
一個具體的超級工廠ConreteFactoryPlus誕生了,他裏面的代碼爲:

public class ConreteFactoryPlus extends ABSFactoryPlus {
    @Override
    public Phone product(String brand) {
        switch (brand) {
            case "黑米":
                MIPhone miPhone = new MIPhone();
                miPhone.brand = "黑米10s";
                miPhone.cup = "驍龍820";
                return miPhone;
            case "三星":
                SumPhone sumPhone = new SumPhone();
                sumPhone.brand = "三星note5";
                sumPhone.cup = "Exynos7420";
                return sumPhone;
            default:
                return null;
        }
    }

    @Override
    public Router newProduct(String brand) {
        switch (brand) {
            case "水星":
                MercuryRouter mercuryRouter = new MercuryRouter();
                mercuryRouter.brand = "水星300";
                mercuryRouter.rate = 300;
                return mercuryRouter;
            case "Link":
                LinkRouter linkRouter = new LinkRouter();
                linkRouter.brand = "Link";
                linkRouter.rate = 1000;
                return linkRouter;
            default:
                return null;
        }
    }
}

它可以同時生產手機和路由器,下面我們來看看Router類的代碼:

public abstract class Router {
    String brand;
    int rate;

   public  abstract void rout();
}

代碼很簡單,只有一個rout方法,來看看其實現類MercuryRouter

public class MercuryRouter extends Router {
    @Override
    public void rout() {
        Log.e("", "我使用:" + brand + "路由器!它的速率爲:" + rate+"M");
    }
}

還有一個LinkRouter類似,就不貼出代碼了,下面我們就來測試這個超級工廠能不能符合我們的要求,修改start裏面的代碼如下:

  public void start(View view) {
        ConreteFactoryPlus conreteFactoryPlus = new ConreteFactoryPlus();
        Router router = conreteFactoryPlus.newProduct("水星");
        Phone phone = conreteFactoryPlus.product("蘋果");
        if (null == phone) {
            Log.e("", "對不起,我們無法爲你生產該型號的手機!");
        } else {
            phone.sendMSG();
            phone.call();
        }
        if (null == router) {
            Log.e("", "對不起,我們無法爲你生產該型號的路由器!");
        } else {
            router.rout();
        }
    }

我們來看運行結構:




我們看到同時生產了兩種產品。搞定!

掃描關注我的微信公衆號:



總結:

使用工廠模式會增加我們類的數量,可是卻能降低各種類的耦合性,也可以隱藏類的創建過程,用戶無需知道類是如何創建的,也無需知道創建的是什麼樣的類,只需要給參數傳進去就可以得到我們的類。以後我們需要創建幾種類似的類的時候我們要優先考慮使用工廠類來代替我們直接new!!ok,今天的模式就到這裏了,如果你想學到更多的設計模式請關注我的博客,期待我的更新吧!


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