Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> java/android 設計模式學習筆記(3)---工廠方法模式

java/android 設計模式學習筆記(3)---工廠方法模式

編輯:關於Android編程

這篇來介紹一下工廠方法模式(Factory Method Pattern),在實際開發過程中我們都習慣於直接使用 new 關鍵字用來創建一個對象,可是有時候對象的創造需要一系列的步驟:你可能需要計算或取得對象的初始設置;選擇生成哪個子對象實例;或在生成你需要的對象之前必須先生成一些輔助功能的對象,這個時候就需要了解該對象創建的細節,也就是說使用的地方與該對象的實現耦合在了一起,不利於擴展,為了解決這個問題就需要用到我們的工廠方法模式,它適合那些創建復雜的對象的場景,工廠方法模式也是一個使用頻率很高的設計模式。
  PS:對技術感興趣的同鞋加群544645972一起交流。

特點

工廠方法模式(Factory Method Pattern)定義了一個創建對象的接口,但由子類決定要實例化的類是哪一個,工廠方法讓類把實例化推遲到子類,這樣的設計將對象的創建封裝其來,以便於得到更松耦合,更有彈性的設計。
  工廠方法模式是創建型設計模式之一,是結構較為簡單的一種模式,在我們平時的開發過程中應用也是非常的廣泛,比如 ArrayList,HashSet,與 Iterator 之間就能算是一種工廠方法。
  簡單工廠模式(Simple Factory)是工廠方法模式的一種,工廠方法模式的特點總結一下:

簡單工廠模式從某種意義上來說不算是真正的設計模式,但仍不失為一個簡單的方法,可以將客戶程序從具體類中解耦;工廠方法模式使用繼承,把對象的創建委托給子類,子類實現工廠方法來創建對象,也就是說允許將實例化延遲到子類進行;;工廠方法模式是一個非常典型的“針對抽象編程,而不是具體類編程”例子。

 

UML類圖

  這裡寫圖片描述
  上圖為工廠方法模式的uml類圖,幾個角色的分工也很明確,主要分為四大模塊:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCtK7ysez6c/zuaSzp73Tv9qjrMbkzqq5pLOnt723qMSjyr21xLrL0MSjrMv8tqjS5cHL0ru49rmks6fA4Mv5vt+xuLXEu/mxvtDQzqqju7b+yse+38zluaSzp6OsxuTKtc/Wwcu+38zltcTStc7xwt+8raO7yP3Kx7Ppz/Oy+sa3vdO/2qOsy/y2qNLlwcvL+dPQsvrGt7XEuau5stDQzqqju8vEyse+38zlsvrGt6OszqrKtc/Ws+nP87L6xre1xMSzuPa+38zlsvrGt7XEttTP86GjvPK1pbmks6fEo8q9us25pLOnt723qMSjyr21xMf4sfC+zdTa09q88rWluaSzp8Sjyr29q7Ppz/O5pLOnvdO/2tXiuPa9x8mruPi+q7zytfTBy6Osyse5pLOnt723qMSjyr21xNK7uPbI9buvsOaxvqGjPGJyIC8+DQqhoaGhtNPV4tbWyei8xrXEvce2yMC0y7y/vKOsuaSzp7e9t6jEo8q9ysfN6sirt/u6z8novMbUrdTytcSjrMv8vau21M/ztcS0tL2ot+LXsMbwwLSjrNLUsePT2rXDtb24/MvJ8e66z6OsuPzT0LWv0NS1xMnovMajrLb4x9K5pLOnt723qMSjyr3SwMC109qz6c/ztcS907/ao6y9q8q1wP27r7XEyM7O8b27uPjX08DgyKXN6rPJo6zT0LfHs6O6w7XEv8nAqbPk0NShow0KPHA+Jm5ic3A7PC9wPg0KPGgxIGlkPQ=="示例與源碼">示例與源碼

  我們以一個簡單的玩具工廠為例,工廠中生產小孩的玩具,女生的玩具和男生的玩具,先寫一個 IToy 的抽象產品接口用來定義玩具的基本行為模式,然後實現該接口生成幾個玩具的具體產品類 ChildrenToy,MenToy 和 WomenToy 類:
IToy.class

public interface IToy {
    /**
     * 名字
     */
    String getName();

    /**
     * 價格
     */
    float price();

    /**
     * 玩
     */
    void play();
}

ChildrenToy.class

public class ChildrenToy implements IToy{
    @Override
    public String getName() {
        return "toy car";
    }

    @Override
    public float price() {
        return 10.5f;
    }

    @Override
    public void play() {
        Log.e("play", "a child is playing a toy car");
    }
}

MenToy.class

public class MenToy implements IToy{
    @Override
    public String getName() {
        return "PS4";
    }

    @Override
    public float price() {
        return 2300;
    }

    @Override
    public void play() {
        Log.e("play", "a man is playing GTA5 on ps4");
    }
}

WomenToy.class

public class WomenToy implements IToy{
    @Override
    public String getName() {
        return "plush toy";
    }

    @Override
    public float price() {
        return 200;
    }

    @Override
    public void play() {
        Log.e("play", "a woman is playing with a plush toy");
    }
}

完成產品的兩個角色之後,接下來要定義工廠類的兩個角色,根據工廠方法模式和簡單工廠模式的不同,可以有兩種不同的寫法:

工廠方法

工廠方法模式需要先寫出一個工廠類的抽象接口來定義行為,這個時候根據實際情況我們可以分為兩種實現方式,第一種寫法會有多個 ConcreteFactory 的角色;第二種寫法只會有一個 ConcreteFactory 的角色,根據傳入的參數不同而返回不同的產品對象:

multi ConcreateFactory

IToyCreator.class

public interface IToyCreator {
    /**
     * 生產玩具
     */
    IToy createToy();
}

ChildrenToyCreator.class

public class ChildrenToyCreator implements IToyCreator {
    private static final String TAG = "ChildrenToyCreator";

    @Override
    public IToy createToy() {
        IToy toy = new ChildrenToy();
        Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
        toy.play();
        return toy;
    }
}

MenToyCreator.class

public class MenToyCreator implements IToyCreator  {
    private static final String TAG = "MenToyCreator";

    @Override
    public IToy createToy() {
        IToy toy = new MenToy();
        Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
        toy.play();
        return toy;
    }
}

WomenToyCreator.class

public class WomenToyCreator implements IToyCreator  {
    private static final String TAG = "WomenToyCreator";

    @Override
    public IToy createToy() {
        IToy toy = new WomenToy();
        Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
        toy.play();
        return toy;
    }
}

最後直接可以根據需要創建不同的 IToy 對象了,測試代碼如下:

IToyCreator toyCreator;
switch (v.getId()) {
    case R.id.btn_child:
        toyCreator = new ChildrenToyCreator();
        toyCreator.createToy();
        break;
    case R.id.btn_men:
        toyCreator = new MenToyCreator();
        toyCreator.createToy();
        break;
    case R.id.btn_women:
        toyCreator = new WomenToyCreator();
        toyCreator.createToy();
        break;
}

single ConcreteFactory

IToyCreator.class

public interface IToyCreator {
    /**
     * 生產玩具
     */
     IToy createToy(Class clazz);
}

ConcreteToyCreator.class

public class ConcreteToyCreator implements IToyCreator{
    private static final String TAG = "ConcreteToyCreator";

    @Override
    public  IToy createToy(Class clazz) {
        if (clazz == null){
            throw new IllegalArgumentException("argument must not be null");
        }
        try {
            IToy toy = clazz.newInstance();
            Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
            toy.play();
            return toy;
        } catch (Exception e) {
            throw new UnknownError(e.getMessage());
        }
    }
}

這種寫法直接傳入一個 Class 對象,接著利用反射的方式進行對象的創建,可以說從某種意義上精簡了很多的工廠實現類,不用一個具體產品類就對應需要一個具體工廠類了,下面為測試代碼:

IToyCreator toyCreator;
switch (v.getId()) {
    case R.id.btn_child:
        toyCreator.createToy(ChildrenToy.class);
        break;
    case R.id.btn_men:
        toyCreator.createToy(MenToy.class);
        break;
    case R.id.btn_women:
        toyCreator.createToy(WomenToy.class);
        break;
}

總結對比

以上的兩種方式當然最後都能夠成功打印出正確的結果:
  這裡寫圖片描述
單個工廠實現類的方法對比前面的多個工廠實現類的方法來說更加的簡潔和動態,而且對於以後新增的產品類來說也能夠不用修改原來的代碼,符合開閉原則,但是這種寫法在某些情況下是不適用的,比如不同的 IToy 對象設置了不同的構造函數,參數都不一樣,用反射來實現就不適用了,這個時候就只能為每一個具體產品類都定義一個對應的具體工廠類了

簡單工廠

同樣是上面的代碼,具體工廠實現類只有一個的時候,我們還是為工廠提供了一個抽象類,那麼,如果將 IToyCreator 這個角色精簡掉,只留下 ConcreteToyCreator 的這個角色,將其中的產品生成方法設置為靜態應該也是沒問題的:

public class ToyCreator{
    private static final String TAG = "ToyCreator";

    public static  IToy createToy(Class clazz) {
        if (clazz == null){
            throw new IllegalArgumentException("argument must not be null");
        }
        try {
            IToy toy = clazz.newInstance();
            Log.e(TAG, "buy a/an " + toy.getName()+" for " + toy.price() + " yuan, and then ---");
            toy.play();
            return toy;
        } catch (Exception e) {
            throw new UnknownError(e.getMessage());
        }
    }
}

像這樣的方式就稱為簡單工廠模式,上面也說過,是工廠方法模式的一個弱化版本,缺點就是失去了被子類繼承的特性,所有的壓力都集中在工廠類中,不利於維護。

總結

總的來說,工廠方法模式是一個很好的設計模式,它遵循了一個“盡可能讓事情保持抽象”的原則,松耦合的設計原則也能夠很好的符合開閉原則,將類的實例化推遲到子類,同時也擯棄了簡單工廠模式的缺點。
  但是同時工廠方法模式也有一些缺點,每次我們為工廠方法添加新的產品時就要編寫一個新的產品類,同時還要引入抽象層,當產品種類非常多時,會出現大量的與之對應的工廠對象,這必然會導致類結構的復雜化,所以對於簡單的情況下,使用工廠方法模式就需要考慮是不是有些“重”了。

源碼下載

  https://github.com/zhaozepeng/Design-Patterns/tree/master/FactoryMethodPattern

 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved