使用策略模式優雅引用第三方框架

fansonq發表於2018-10-20

為什麼要使用策略模式引用?

在Android開發過程中,我們一般都會使用到第三方框架,隨著框架層出不窮,隨著專案的發展擴大,不排除會出現替換框架的情況,例如:日誌框架,圖片框架,網路框架等等;最初我在開發過程中會直接引用第三方框架,直到後來需要替換框架的時候,才發現這個過程的工作量是巨大並且沒意義的,需要修改使用到框架的地方有幾十處(如果專案大,遠遠不止這個數目),那時候我就醒悟,一定要培養架構思想,不能應付式的實現了功能就認為萬事大吉。後來在學習過程中發現,使用策略模式可以很友好的解決框架更換的問題,並且可以通過一句程式碼就輕鬆切換整個專案的框架。


    不使用策略模式封裝也可以呀!

    或許會有讀者認為沒必要使用策略模式這麼麻煩,只需要將框架進行二次封裝,待需要修改的時候也可以不影響其他程式碼。對於這種思路,我用圖片框架Universal-Image-Loader作為例子簡單描述一下,貼上簡短的程式碼便於清晰。

    /**
    * 簡單封裝Universal-Image-Loader圖片載入的工具類
    **/
    public class ImageLoaderUtils {
    
        private DisplayImageOptions mImageOptions;
    
        public ImageLoaderUtils(){
            //配置UIL的初始化
            ImageLoaderConfiguration configuration = ImageLoaderConfiguration.createDefault(this); 
            ImageLoader.getInstance().init(configuration);
    
            mImageOptions = DisplayImageOptions.createSimple();
        }
    
        //預設載入
        public static void loadImageView(Context context, String imgUrl, ImageView view) {
            ImageLoader.getInstance().displayImage(imgUrl, view, mImageOptions);
        }
    
    }複製程式碼


    封裝好的工具類在Activity中的示範如下:

    /**
    * ImageLoaderUtils的使用示範
    **/
    public class ExampleActivity extends AppCompatActivity{
        
        private ImageView mIvPhoto;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test);
    
            mIvPhoto = findViewById(R.id.iv_cover);
            
            ImageLoaderUtils.loadImageView(this,"url",mIvPhoto);
        }
    }複製程式碼

    如果需要使用Glide框架替換現在的Universal-Image-Loader框架,直接修改ImageLoaderUtils工具類,這樣亦可實現不需修改所有使用到框架Universal-Image-Loader的地方。

    /**
    * 使用Glide替換Universal-Image-Loader的工具類
    **/
    public class ImageLoaderUtils {    
    
        //預設載入
        public static void loadImageView(Context context, String imgUrl, ImageView view) {
            Glide.with(context).load(imgUrl).into(view);
        }
    
    }複製程式碼

    這樣處理固然可以替換框架,並且工作量不算大,但我認為這種處理方式有一定的弊端,剔除了舊框架程式碼,萬一日後新框架出現問題,處理工作就顯得麻煩,說白了就是這種處理方式不能並存兩種或兩種以上的框架方案,如果專案中需要切換框架的話就明顯感覺到不靈活,所以我認為引入策略模式是可取的。


    開啟封裝之路

    關於策略模式,這裡我就不詳細描述,日後抽空寫一篇關於“策略模式”的文章。

    首先,我們定義一個策略介面,用於存放框架之間會共同使用的方法,例如:預設載入圖片,載入GIf等等。

        /**
        * 策略介面
        **/
       public interface BaseImageLoaderStrategy {
    
           /**
            * 預設方式載入圖片
            * @param context 上下文
            * @param view View 控制元件
            * @param imgUrl 圖片URL
            */
           void loadImage(Context context, ImageView view, Object imgUrl);
    
    }
    複製程式碼


    第二步:接下來寫實現類,這裡我使用Universal-Image-Loader為例,簡單寫一個實現類。

    /**
    * Universal-Image-Loader的實現類
    **/
    public class UniversalLoaderStrategy implements BaseImageLoaderStrategy {
    
       private DisplayImageOptions mImageOptions;
    
       /**
       * 初始化載入配置
       */
       private void initOptions() {   
            ImageLoaderConfiguration configuration = ImageLoaderConfiguration.createDefault(this); 
            ImageLoader.getInstance().init(configuration);
    
            mImageOptions = DisplayImageOptions.createSimple();
       }   
    
        @Override
        public void loadImage(Context context, ImageView view, Object imgUrl) {
            ImageLoader.getInstance().displayImage(imgUrl, view, mImageOptions);
        }
    
    }複製程式碼


    完成實現類後,最後寫一個呼叫的工具類就完成了封裝。

    /**
    * 呼叫圖片框架的工具類
    **/
    public class ImageLoaderUtils {
    
        private BaseImageLoaderStrategy mImageLoaderStrategy;
    
        private ImageLoaderUtils() {
            //預設使用Universal-Image-Loader
            mImageLoaderStrategy = new UniversalLoaderStrategy();    }
    
       /**
        * 設定圖片框架策略
        * @param strategy  圖片框架策略
        **/
        public static void setImageLoaderStrategy(BaseImageLoaderStrategy strategy) {
            if (strategy != null) {
                mImageLoaderStrategy = strategy;
            }
        }
    
    
       /**
        * 呼叫預設載入圖片
        **/
        public static void loadImage( Context context, ImageView view, Object imgUrl) {
            mImageLoaderStrategy.loadImage(context,view,imgUrl);
        }
    }複製程式碼


    到此為止,就已經完成了初步的封裝,使用方式:

    ImageLoaderUtils.loadImage(context, imageView, imgUrl);複製程式碼


    完成了初步封裝,但如何解決框架替換的問題好像還沒提及到。兄弟不要急呀,車現在馬上要開,扶穩了。假如專案現在要使用Glide框架,那我們需要先寫一個簡單Glide的實現類。如下:

    /**
    * Glide的實現類
    **/
    public class GlideLoaderStrategy implements BaseImageLoaderStrategy {
    
       private RequestOptions mOptions;
       private ImageLoaderConfig mConfig;
    
       /**
       * 初始化載入配置
       */
       private RequestOptions getOptions() {
        if (mOptions == null) {
            mOptions = new RequestOptions();
            mOptions.error(mConfig.getErrorPicRes())
                    .placeholder(mConfig.getPlacePicRes())
                    //下載的優先順序
                    .priority(Priority.NORMAL)
                    //快取策略
                    .diskCacheStrategy(DiskCacheStrategy.ALL);
           }
         return mOptions;
       }   
    
        @Override
        public void loadImage(Context context, ImageView view, Object imgUrl) {
            with(context)
                    .load(imgUrl)
                    .apply(getOptions())
                    //先載入縮圖 然後在載入全圖
                    .thumbnail(Contants.THUMB_SIZE)
                    .into(view);
        }
    
    }複製程式碼


    搞定了Glide的實現類後,呼叫ImageLoaderUtils的setImageLoaderStrategy方法即可實現框架的替換,並且不影響其他程式碼。

    //切換成Glide框架
    ImageLoaderUtils.setImageLoaderStrategy(new GlideLoaderStrategy());複製程式碼

    主要思想大概就是這樣,但實際專案中的封裝並沒有這麼簡單,為了描述這種思想,所以簡單化,在此我貼上原始碼地址:https://github.com/fansonq/ImageLoaderUtils,有興趣的讀者不妨下載閱讀,更深的瞭解(原始碼有註釋)。

    看完圖片框架的封裝,大家不妨嘗試封裝日誌框架進行理解並鞏固,將這種思想融會貫通。

    如果這篇文章寫的有錯漏,懇請留言提示糾正;如果有什麼地方描述的不夠清晰,留下評論,我看到會給予回覆,一起交流;如果這篇文章對你有所幫助,不妨點選“喜歡”給予支援,日後我會努力抽空分享自我覺得不錯的知識點給大家。



    相關文章