why? 封裝
Android 發(fā)展到現(xiàn)在這個(gè)時(shí)期, 出現(xiàn)了各種成熟好用的第三方框架, 使用這些第三方框架來完成我們自己的App的功能是很方便的. 但是最好不要直接的去使用這些第三方框架, 因?yàn)榭赡茈S著項(xiàng)目的功能迭代, 一開始確定的框架后來并不能滿足我們的需求, 這個(gè)時(shí)候如果沒有做封裝, 要修改它們就是一個(gè)繁雜的事情了. 因此需要對框架進(jìn)行封裝. 還有一個(gè)好處就是方便修改統(tǒng)一的配置.
how? 封裝
通常我們封裝一個(gè)框架都是會(huì)寫一些工具類,然后通過工具類來完成功能的封裝, 這樣寫,當(dāng)然是OK的, 但是真到了需要換框架的時(shí)候, 做修改可能需要把以前寫的代碼都刪除掉, 然后寫上新的代碼, 這樣做并不好,有沒有一個(gè)辦法, 就是說新的代碼在加上的時(shí)候老的代碼不需要?jiǎng)h除掉, 只是做不同的配置呢. 這樣一來如果的新的東西有問題, 還是可以及時(shí)配置成之前的. 這樣就降低了開發(fā)的風(fēng)險(xiǎn),增加了代碼的靈活度. 這里就需要使用策略模式來完成了.
舉個(gè)栗子
今天就以圖片框架舉栗子, 看看怎么使用策略模式進(jìn)行封裝.
對于圖片加載框架,大家用到的可能是Glide,Picasso或者Fresco,這基本上是主流的圖片加載框架.
先看Glide加載圖片的代碼:
Glide.with(getContext())
.load(url)
.skipMemoryCache(true)
.placeholder(drawable)
.centerCrop()
.animate(animator)
.into(img);
定義策略
不管是什么圖片加載框架都是需要做一些配置的. 把這些配置封裝起來. 配置中相同的東西可以抽取出去.
如下
public class ImageLoaderOptions {
//你可以把三個(gè)圖片加載框架所有的共同或相似設(shè)置項(xiàng)搬過來,現(xiàn)在僅僅用以下幾種作為范例演示。
private int placeHolder = -1; //當(dāng)沒有成功加載的時(shí)候顯示的圖片
private ImageReSize size = null; //重新設(shè)定容器寬高
private int errorDrawable = -1; //加載錯(cuò)誤的時(shí)候顯示的drawable
private boolean isCrossFade = false; //是否漸變平滑的顯示圖片
private boolean isSkipMemoryCache = false; //是否跳過內(nèi)存緩存
private ViewPropertyAnimation.Animator animator = null; // 圖片加載動(dòng)畫
private ImageLoaderOptions(ImageReSize resize, int placeHolder, int errorDrawable, boolean isCrossFade, boolean isSkipMemoryCache, ViewPropertyAnimation.Animator animator) {
this.placeHolder = placeHolder;
this.size = resize;
this.errorDrawable = errorDrawable;
this.isCrossFade = isCrossFade;
this.isSkipMemoryCache = isSkipMemoryCache;
this.animator = animator;
}
public class ImageReSize {
int reWidth = 0;
int reHeight = 0;
public ImageReSize(int reWidth, int reHeight) {
if (reHeight <= 0) {
reHeight = 0;
}
if (reWidth <= 0) {
reWidth = 0;
}
this.reHeight = reHeight;
this.reWidth = reWidth;
}
}
public int getPlaceHolder() {
return placeHolder;
}
public void setPlaceHolder(int placeHolder) {
this.placeHolder = placeHolder;
}
public ImageReSize getSize() {
return size;
}
public void setSize(ImageReSize size) {
this.size = size;
}
public int getErrorDrawable() {
return errorDrawable;
}
public void setErrorDrawable(int errorDrawable) {
this.errorDrawable = errorDrawable;
}
public boolean isCrossFade() {
return isCrossFade;
}
public void setCrossFade(boolean crossFade) {
isCrossFade = crossFade;
}
public boolean isSkipMemoryCache() {
return isSkipMemoryCache;
}
public void setSkipMemoryCache(boolean skipMemoryCache) {
isSkipMemoryCache = skipMemoryCache;
}
public ViewPropertyAnimation.Animator getAnimator() {
return animator;
}
public static final class Builder {
private int placeHolder=-1;
private ImageReSize size=null;
private int errorDrawable=-1;
private boolean isCrossFade =false;
private boolean isSkipMemoryCache = false;
private ViewPropertyAnimation.Animator animator = null;
public Builder (){
}
public Builder placeHolder(int drawable){
this.placeHolder=drawable;
return this;
}
public Builder reSize(ImageReSize size){
this.size=size;
return this;
}
public Builder anmiator(ViewPropertyAnimation.Animator animator){
this.animator=animator;
return this;
}
public Builder errorDrawable(int errorDrawable){
this.errorDrawable=errorDrawable;
return this;
}
public Builder isCrossFade(boolean isCrossFade){
this.isCrossFade=isCrossFade;
return this;
}
public Builder isSkipMemoryCache(boolean isSkipMemoryCache){
this.isSkipMemoryCache=isSkipMemoryCache;
return this;
}
public ImageLoaderOptions build(){
return new ImageLoaderOptions(this.size,this.placeHolder,this.errorDrawable,this.isCrossFade,this.isSkipMemoryCache,this.animator);
}
}
}
定義策略的接口
public interface ImageLoaderStrategy {
void showImage(View v, String url,ImageLoaderOptions options);
void showImage(View v, int drawable,ImageLoaderOptions options);
}
策略的實(shí)現(xiàn)類 在這里用的是glide來加載圖片的
public class GlideImageLoaderStrategy implements ImageLoaderStrategy {
@Override
public void showImage(View v, String url, ImageLoaderOptions options) {
if (v instanceof ImageView) {
//將類型轉(zhuǎn)換為ImageView
ImageView imageView= (ImageView) v;
//裝配基本的參數(shù)
DrawableTypeRequest dtr = Glide.with(imageView.getContext()).load(url);
//裝配附加參數(shù)
loadOptions(dtr, options).into(imageView);
}
}
@Override
public void showImage(View v, int drawable, ImageLoaderOptions options) {
if (v instanceof ImageView) {
ImageView imageView= (ImageView) v;
DrawableTypeRequest dtr = Glide.with(imageView.getContext()).load(drawable);
loadOptions(dtr, options).into(imageView);
}
}
//這個(gè)方法用來裝載由外部設(shè)置的參數(shù)
private DrawableTypeRequest loadOptions(DrawableTypeRequest dtr,ImageLoaderOptions options){
if (options==null) {
return dtr;
}
if (options.getPlaceHolder()!=-1) {
dtr.placeholder(options.getPlaceHolder());
}
if (options.getErrorDrawable()!=-1){
dtr.error(options.getErrorDrawable());
}
if (options.isCrossFade()) {
dtr.crossFade();
}
if (options.isSkipMemoryCache()){
dtr.skipMemoryCache(options.isSkipMemoryCache());
}
if (options.getAnimator()!=null) {
dtr.animate(options.getAnimator());
}
if (options.getSize()!=null) {
dtr.override(options.getSize().reWidth,options.getSize().reHeight);
}
return dtr;
}
}
加載圖片定義接口
public interface ImageLoader {
void showImage(@NonNull View mView, @NonNull String mUrl);
void showImage(@NonNull View mView, @NonNull int mDraeables);
}
管理類去實(shí)現(xiàn)這個(gè)接口.
public class ImageLoaderManager implements ImageLoader{
private static final ImageLoaderManager INSTANCE = new ImageLoaderManager();
private ImageLoaderStrategy imageLoader;
private ImageLoaderOptions options;
private ImageLoaderManager() {
//默認(rèn)使用Glide --> 在這里修改默認(rèn)的圖片加載框架
imageLoader = new GlideImageLoaderStrategy();
options = new ImageLoaderOptions.Builder().build();
}
public static ImageLoaderManager getInstance() {
return INSTANCE;
}
//可實(shí)時(shí)替換圖片加載框架
public void setImageLoader(ImageLoaderStrategy loader) {
if (loader != null) {
imageLoader = loader;
}
}
@Override
public void showImage(@NonNull View mView, @NonNull String mUrl) {
imageLoader.showImage(mView, mUrl, options);
}
@Override
public void showImage(@NonNull View mView, @NonNull int mDraeables) {
imageLoader.showImage(mView, mDraeables, options);
}
}
使用
ImageLoaderManager.getInstance().showImage(iv,URL1);
總結(jié)
使用策略模式封裝的思路.
- 先定義出Manager的接口來約束Manger類,可以做什么事情, 這里面參數(shù)應(yīng)該是盡可能的少.
- 接口有了, manager類的實(shí)現(xiàn)可以寫了 manager類中需要定義 策略 和 參數(shù). 通過這些變量完成接口中需要實(shí)現(xiàn)的功能. 變量應(yīng)該在構(gòu)造函數(shù)中完成初始化.
- 定義策略類的接口
- 接口的實(shí)現(xiàn)類, 圖片有三種網(wǎng)絡(luò)框架,這里就可以定義三個(gè)策略的實(shí)現(xiàn)類. 每個(gè)實(shí)現(xiàn)類中去完成不同的圖片加載方式.