定义
策略模式定义了一系列算法,并将每一个算法封装起来,而且使他们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。通俗的讲就是通过动态注入不同的对象或实现来动态替换某种具体行为。
使用场景
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别
2.需要安全的封装多种同一类型的操作
3.出现同一抽象类有多个子类,而又需要使用条件语句来选择 具体子类时
关键点
一个抽象的策略或算法
一个或多个具体的抽象实现
一个操作策略或算法的上下文,持有抽象,可以动态注入具体实现
实现
以一个项目开发中的图片加载框架为例:通常做项目的时候,我们会选取一个第三方的框架去处理图片问题,比如加载缓存等。于是在选取的时候我们就不得不考虑几个问题:
1.软件升级时框架升级
2.低耦合,调用简单
3.管理方便
设计思路
将图片加载策略抽象出来,对外提供接口,隐藏内部实现细节。可动态注入进行策略升级。
/**
* 图片加载策略定义(显示图片的策略)
*/
public interface ImageLoaderStrategy {
/**
* @param imageView
* @param url 图片资源地址
*/
void displayImage(ImageView imageView, String url);
/**
* @param imageView
* @param url 图片资源地址
* @param placeholder 占位图片资源id
* @param error 加载失败图片资源id
*/
void displayImage(ImageView imageView, String url, int placeholder, int error);
/**
* @param imageView
* @param url 图片资源地址
* @param corner 图片圆角
*/
void displayCornerImage(ImageView imageView, String url, int corner);
}
/**
* Glide图片加载策略
*/
public class GlideImageLoader implements ImageLoaderStrategy {
@Override
public void displayImage(ImageView imageView, String url) {
Glide.with(imageView.getContext())
.load(url)
.into(imageView);
}
@Override
public void displayImage(ImageView imageView, String url, int placeholder, int error) {
Glide.with(imageView.getContext())
.load(url)
.placeholder(placeholder)
.error(error)
.into(imageView);
}
@Override
public void displayCornerImage(ImageView imageView, String url, int corner) {
}
}
/**
* Picasso加载策略
*/
public class PicassoImageLoader implements ImageLoaderStrategy {
@Override
public void displayImage(ImageView imageView, String url) {
Picasso.with(imageView.getContext())
.load(url)
.into(imageView);
}
@Override
public void displayImage(ImageView imageView, String url, int placeholder, int error) {
Picasso.with(imageView.getContext())
.load(url)
.placeholder(placeholder)
.error(error)
.into(imageView);
}
@Override
public void displayCornerImage(ImageView imageView, String url, int corner) {
}
}
/**
* 图片加载上下文 持有图片加载策略、单例对外提供
*/
public class ImageLoader {
private ImageLoaderStrategy mImageLoad;
/**
* 动态注入加载策略
*
* @param imageLoadStrategy 具体的加载策略
*/
public void setImageLoadStrategy(ImageLoaderStrategy imageLoadStrategy) {
this.mImageLoad = imageLoadStrategy;
}
/**
* 对外提供的加载方法
*
* @param imageView
* @param url
*/
public void displayImage(ImageView imageView, String url) {
mImageLoad.displayImage(imageView, url);
}
/**
* * 对外提供的加载方法 携带占位符和加载失败显示的图片资源Id
*
* @param imageView
* @param url
* @param placeholder
* @param error
*/
public void displayImage(ImageView imageView, String url, int placeholder, int error) {
mImageLoad.displayImage(imageView, url, placeholder, error);
}
/**
* 加载圆角图片
*
* @param imageView
* @param url
* @param corner
*/
public void displayCornerImage(ImageView imageView, String url, int corner) {
mImageLoad.displayCornerImage(imageView, url, corner);
}
/**
* 私有化构造函数
*/
private ImageLoader() {
}
public static ImageLoader getInstance() {
return ImageLoadHolder.INSTANCE;
}
public static final class ImageLoadHolder {
private static final ImageLoader INSTANCE = new ImageLoader();
}
}
使用
//在项目初始化的时候注入具体的图片加载策略
ImageLoader.getInstance().setImageLoadStrategy(new GlideImageLoader());
ImageLoader.getInstance().displayImage(imageView, "http://pic4.nipic.com/20091217/3885730_124701000519_2.jpg");
小结:
策略模式主要用来分离算法,在相同的行为抽象下具有不同的具体实现策略,很好的演示了开闭原则即定义抽象,注入不同实现,具有很好的扩展性。
优点:
1.结果清晰明了、使用简单直观
2.耦合度相对而言极低,扩展方便
3.操作封装更为彻底,数据更为安全
缺点:
每增加一种策略,子类会添加