why? 封装
Android 发展到现在这个时期, 出现了各种成熟好用的第三方框架, 使用这些第三方框架来完成我们自己的App的功能是很方便的. 但是最好不要直接的去使用这些第三方框架, 因为可能随着项目的功能迭代, 一开始确定的框架后来并不能满足我们的需求, 这个时候如果没有做封装, 要修改它们就是一个繁杂的事情了. 因此需要对框架进行封装. 还有一个好处就是方便修改统一的配置.
how? 封装
通常我们封装一个框架都是会写一些工具类,然后通过工具类来完成功能的封装, 这样写,当然是OK的, 但是真到了需要换框架的时候, 做修改可能需要把以前写的代码都删除掉, 然后写上新的代码, 这样做并不好,有没有一个办法, 就是说新的代码在加上的时候老的代码不需要删除掉, 只是做不同的配置呢. 这样一来如果的新的东西有问题, 还是可以及时配置成之前的. 这样就降低了开发的风险,增加了代码的灵活度. 这里就需要使用策略模式来完成了.
举个栗子
今天就以图片框架举栗子, 看看怎么使用策略模式进行封装.
对于图片加载框架,大家用到的可能是Glide,Picasso或者Fresco,这基本上是主流的图片加载框架.
先看Glide加载图片的代码:
Glide.with(getContext())
.load(url)
.skipMemoryCache(true)
.placeholder(drawable)
.centerCrop()
.animate(animator)
.into(img);
定义策略
不管是什么图片加载框架都是需要做一些配置的. 把这些配置封装起来. 配置中相同的东西可以抽取出去.
如下
public class ImageLoaderOptions {
//你可以把三个图片加载框架所有的共同或相似设置项搬过来,现在仅仅用以下几种作为范例演示。
private int placeHolder = -1; //当没有成功加载的时候显示的图片
private ImageReSize size = null; //重新设定容器宽高
private int errorDrawable = -1; //加载错误的时候显示的drawable
private boolean isCrossFade = false; //是否渐变平滑的显示图片
private boolean isSkipMemoryCache = false; //是否跳过内存缓存
private ViewPropertyAnimation.Animator animator = null; // 图片加载动画
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);
}
策略的实现类 在这里用的是glide来加载图片的
public class GlideImageLoaderStrategy implements ImageLoaderStrategy {
@Override
public void showImage(View v, String url, ImageLoaderOptions options) {
if (v instanceof ImageView) {
//将类型转换为ImageView
ImageView imageView= (ImageView) v;
//装配基本的参数
DrawableTypeRequest dtr = Glide.with(imageView.getContext()).load(url);
//装配附加参数
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);
}
}
//这个方法用来装载由外部设置的参数
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);
}
管理类去实现这个接口.
public class ImageLoaderManager implements ImageLoader{
private static final ImageLoaderManager INSTANCE = new ImageLoaderManager();
private ImageLoaderStrategy imageLoader;
private ImageLoaderOptions options;
private ImageLoaderManager() {
//默认使用Glide --> 在这里修改默认的图片加载框架
imageLoader = new GlideImageLoaderStrategy();
options = new ImageLoaderOptions.Builder().build();
}
public static ImageLoaderManager getInstance() {
return INSTANCE;
}
//可实时替换图片加载框架
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);
总结
使用策略模式封装的思路.
- 先定义出Manager的接口来约束Manger类,可以做什么事情, 这里面参数应该是尽可能的少.
- 接口有了, manager类的实现可以写了 manager类中需要定义 策略 和 参数. 通过这些变量完成接口中需要实现的功能. 变量应该在构造函数中完成初始化.
- 定义策略类的接口
- 接口的实现类, 图片有三种网络框架,这里就可以定义三个策略的实现类. 每个实现类中去完成不同的图片加载方式.