Design Patterns in Android:工廠方法模式

前言

今天給你們分享的是《設計模式Android篇:工廠方法模式》。
工廠方法是建立型模式的一種,可用來在適當的場合建立對象。今天將經過Android源碼和Android開發案例跟你們講解什麼是工廠方法模式。
點擊此處查看《Design Patterns in Android》系列其餘文章。android

本文原創做者MichaelX,博客連接:juejin.im/user/56efe6…,轉載請註明出處。git


工廠方法模式定義

工廠方法模式(Factory method pattern)定義一個接口用於建立對象,可是讓子類決定初始化哪一個類。工廠方法把一個類的初始化下放到子類。程序員


工廠方法模式UML類圖

工廠方法模式UML類圖
工廠方法模式UML類圖

工廠方法各角色講解github

  • IFactory:工廠接口,生產IProduct實例
  • IProduct:產品接口/抽象類
  • FactoryA:生產ProductA產品
  • FactoryB:生產ProductB產品
  • ProductA:一種產品,代號爲A

工廠方法模式示例代碼

IFactory設計模式

public interface IFactory {
    IProduct create();
}複製代碼

IProduct 框架

public interface IProduct {
    void doSomething();
}複製代碼

ProductAide

public class ProductA implements IProduct {

    @Override
    public void doSomething() {
        System.out.println("lalala...我是IProduct的實現類A。");
    }

}複製代碼

FactoryAspa

public class implements IFactory {
    public IProduct create() {
        return new ProductA();
    }

}複製代碼

可是:上述的標準的工廠方法模式一般伴隨着對象的具體類型與工廠具體類型的一一對應,客戶端代碼根據須要選擇合適的具體類型工廠使用,這種選擇可能包含複雜的邏輯。.net

就比如說,我有10種產品,到生產的時候,你要我高層模塊去根據產品選擇合適的工廠來生產嗎?因此就應運而生了一種-簡單工廠模式:簡單工廠類有一個靜態工廠方法,能夠根據高層模塊的輸入參數而生產合適的產品返回,好比:設計

public class SimpleFactory {

    public static  
  
  
  

 
  
  T create(Class 
 
  
    clazz) { IProduct product = null; try { product = (IProduct) Class.forName(clazz.getName()).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return (T) product; } } 
   

 複製代碼

上述的簡單工廠例子中使用了Class做爲輸入參數,這是不固定,參數也能夠是其餘,你們根絕場景自定義。

Android源碼中的工廠方法模式

暫時未在Framework經常使用類中找到很純粹的工廠方法模式,此處待補充。有同窗知道的請留言,謝謝!


Android開發中的工廠方法模式實踐

假如:你在項目中使用了Universal Image Loader做爲圖片加載框架,過一段時間後,發現UIL已經不流行了,想用更加fashion的Glide來代替土老帽UIL。咋辦?新手程序員,可能就想,既然這樣,那就改唄,全部用到UIL的地方,通通拋掉,拋掉。項目小還好,改吧改吧就完了,項目大點,改壞了咋整?版本回退?惋惜的是,不少新手程序員可能連版本控制不用。萬一要是哪一天,連Glide都不更新了,或者說不fashion了,又要換其餘圖片加載框架,難道又改嗎?人都要瘋了好嗎?

這個時候,工廠方法可能能夠幫上忙:使用工廠類隔離圖片加載的具體實現,對外只暴露一個工廠方法用來外部生產想要的加載框架實例,就可避免上述提到的尷尬。口說無憑,上代碼:

圖片加載接口

/**
 * 圖片加載接口
 */
public interface ImageLoaderInterf {
    interface CallBack {
        void onSuccess(Bitmap result);
        void onFailure();
    }

    void load(Context context, String imgUrl, ImageView view);
}複製代碼

圖片加載工廠類

public class ImgLoaderClientFactory {
    public static final GLIDE = 0;
    public static final UIL = 1;
    public static final PICASSO = 2;

    public static ImageLoaderInterf getImageLoaderClient(int type) {
        switch (type) {
            case GLIDE:
                return GlideClient.getInstance();

            case UIL:
                return UilClient.getInstance();

            default:
                return PicassoClient.getInstance();
        }
    }
}複製代碼

UilClient:Universal Image Loader封裝

public class UilClient implements ImageLoaderInterf {

    private static UilClient sInstance;

    private UilClient() {}

    public static UilClient getInstance() {
        synchronized (UilClient.class) {
            if (sInstance == null) {
                sInstance = new UilClient();
            }
        }
        return sInstance;
    }

    @Override
    public void load(Context context, String imgUrl, ImageView view) {
        ImageLoader.getInstance().displayImage(imgUrl, view);
    }
}複製代碼

GlideClient:Glide的二次封裝

public class GlideClient implements ImageLoaderInterf {
    private static GlideClient sInstance;

    private GlideClient() {}

    public static GlideClient getInstance() {
        synchronized (GlideClient.class) {
            if (sInstance == null) {
                sInstance = new GlideClient();
            }
        }
        return sInstance;
    }

    @Override
    public void load(Context context, String imgUrl, ImageView view) {
        Glide.with(context).load(imgUrl).into(view);
    }
}複製代碼

PicassoClient:Picasso封裝類

public class PicassoClient implements ImageLoaderInterf {

    private static PicassoClient sInstance;

    private PicassoClient() {
    }

    public static PicassoClient getInstance() {
        synchronized (PicassoClient.class) {
            if (sInstance == null) {
                sInstance = new PicassoClient();
            }
        }
        return sInstance;
    }

    @Override
    public void load(Context context, String imgUrl, ImageView view) {
        Picasso.with(context).load(imgUrl).into(view);
    }
}複製代碼

那麼加載圖片就變成了下面這樣:

ImgLoaderClientFactory.getImageLoaderClient(ImgLoaderClientFactory.UIL)
.load(mContext, imgUrl, imageView);複製代碼

要切換圖片框架呢?怎麼辦?全局搜索替換ImgLoaderClientFactory.UIL便可,好比想切到Glide,將用到ImgLoaderClientFactory.UIL地方改爲ImgLoaderClientFactory.GLIDE便可。

ImgLoaderClientFactory.getImageLoaderClient(ImgLoaderClientFactory.GLIDE)
.load(mContext, imgUrl, imageView);複製代碼

本文原創做者:MichaelX,博客地址:juejin.im/user/56efe6…

歡迎光臨:MichaelX's Blog

總結

工廠方法適用於:隔離客戶端與待使用的目標產品,用工廠來生產目標產品便可。

好了,今天的《設計模式Android篇:工廠方法模式》就到這裏,請繼續關注《Design Patterns in Android》(設計模式Android篇)系列博文,歡迎各位讀者朋友評論區拍磚交流,共同進步。

相關文章
相關標籤/搜索