背景:
之前项目中使用的是ImageLoader来加载图片,由于Android-Universal-Image-Loader存在着诸多局限性,项目采用Picasso来代替传统实现方式。(Picasso的使用)
在更换方案时,发现一项很棘手的事,由于前期考虑不足,导致技术更换时候,诸多地方调用,使耦合性太高,只能部分做替换或新用到时才有新技术。
策略模式的使用,合理的解决了这一问题。
策略设计模式
策略模式是指对一系列的算法定义,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
策略模式的优点有:策略模式提供了管理相关的算法族的办法、策略模式提供了可以替换继承关系的办法、使用策略模式可以避免使用多重条件转移语句。 (摘自百度百科词条)
策略模式是对算法的包装,把“算法”的责任和本身隔离开,委派给不同的对象管理。简单来说,就是定义一系列的算法,并把它们一个个封装起来,并使它们可以相互替换。
模式如下:
这里涉及到3个角色
1.环境。
2.抽象策略。这是一个抽象角色,通常由一个接口或者抽象类实现,给出所有具体角色需要实现的方法。
3.具体策略。具体策略执行的算法
以图片加载为例,当Adapter绑定数据时:
传统的图片加载方式
public class MainAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public MainAdapter(@Nullable List<String> data) {
super(R.layout.item_main, data);
}
@Override
protected void convert(BaseViewHolder helper, String url) {
// 传统方式加载
GlideApp.with(mContext)
.load(url)
.into((ImageView) helper.getView(R.id.iv_bg));
}
}
这样加载图片就像我们之前项目中使用一样,如果需要更换图片加载库,导致每一个地方都需要修改,工作量大暂且不说,这样每个地方都需改动很容易出问题。结果就是,像我们的项目一样,不得不ImageLoader和Picasso共存,之后再一点点迁移。
而使用合理的模式来进行设计,择避免了这一问题。
运用策略模式来实现
直接上代码:
1.定义抽象策略
/**
* 描述:图片加载策略接口
*
* @author yangjiaming
* @date 2018/2/5
*/
public interface IImageDisplayer {
/**
* 图片加载
*
* @param context
* @param url
* @param imageView
*/
void display(Context context, String url, ImageView imageView);
/**
* 图片加载
*
* @param context
* @param url
* @param imageView
*/
void display(Context context, String url, ImageView imageView , int defultImage , int errorImage);
}
2.具体策略实现,并执行具体的算法
如,通过Glide来加载图片:
/**
* 描述:Gilde方式加载图片
*
* @author yangjiaming
* @date 2018/2/5
*/
public class GlideImageDisplayer implements IImageDisplayer {
@Override
public void display(Context context, String url, ImageView imageView) {
Glide.with(context)
.load(url)
.into(imageView);
}
@Override
public void display(Context context, String url, ImageView imageView, int defultImage, int errorImage) {
GlideApp.with(context)
.load(url)
.error(errorImage)
.placeholder(defultImage)
.into(imageView);
}
}
or 通过Picasso加载图片:
/**
* 描述:picasso方式加载图片
*
* @author yangjiaming
* @date 2018/2/5
*/
public class PicassoImageDisplayer implements IImageDisplayer {
@Override
public void display(Context context, String url, ImageView imageView) {
Picasso.with(context)
.load(url)
.into(imageView);
}
@Override
public void display(Context context, String url, ImageView imageView, int defultImage, int errorImage) {
Picasso.with(context)
.load(url)
.error(errorImage)
.placeholder(defultImage)
.into(imageView);
}
}
3.定义环境
/**
* 描述:图片加载策略管理类
*
* @author yangjiaming
* @date 2018/2/5
*/
public class ImageLoadTools {
public IImageDisplayer getDisplayer() {
return new GlideImageDisplayer();
}
/********************** 单例 **********************/
private ImageLoadTools() {
}
private static final class ImageLoadHolder {
private static final ImageLoadTools instance = new ImageLoadTools();
}
public static ImageLoadTools getInstance() {
return ImageLoadHolder.instance;
}
}
这样一个策略模式框架,就搭建好了,再次回到当Adapter绑定数据时,我们加载图片,就可以这样实现:
/**
* Created by yangjiaming on 2017/12/11.
*/
public class MainAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public MainAdapter(@Nullable List<String> data) {
super(R.layout.item_main, data);
}
@Override
protected void convert(BaseViewHolder helper, String url) {
/**
* 调用策略管理类加载图片
*/
ImageLoadTools.getInstance().getDisplayer().display(mContext, url, (ImageView) helper.getView(R.id.iv_bg));
}
}
当我们需要使用Picasso加载图片时,仅需更改策略管理类即可,
public IImageDisplayer getDisplayer() {
return new PicassoImageDisplayer();
}
科技在飞速发展,技术的更新也是,即使某天Picasso不再被维护被大众所抛弃,我们也无需担心,只需再新建一个类,执行新的算法,去调用新的算法即可。大大增加了代码的拓展性、可移植性。
总结:在开发新的产品时,开发前一定进行前期设计,多考虑一些可能出现的状况,灵活运用设计模式。如今天说的策略设计模式,在网络请求、图片加载… 好多地方都可以使用到。合理的程序设计,使我们代码更加健壮、更易于理解、更易于维护。