7

扫盲:策略模式,成事儿还需要策略

 3 years ago
source link: https://www.daqianduan.com/17369.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

什么是策略模式?

生活中的策略

策略模式在生活中体现很多。

我们要去旅游,我们可以选择不同的出行方式:飞机,火车,大巴,自驾等,这是不同的策略。

双十一当当网购买满减活动,满 100 减 50,满 200 减 100,满 400 减 250 等,这也是不同的策略。

抑或是我们在追求女生时,针对不同性格的女孩子采用不同的方式,这还是不同的策略。

程序中的策略

策略模式在程序中的体现依然淋漓尽致。

比如我们的图片加载,Android 上有 FrescoPicassoGlideUniversal-Image-Loader 等,iOS 上有 SDWebImageAFNetworkingFastImageCache 等。

所以,假设让你来设计一个图片加载上层框架,要求可以底层可以使用 A B 两种加载策略,你会怎么做呢?

// 加载类A 
public class ImageLoadServiceA {
    public void loadImage() {
        System.out.println("使用 A 加载框架");
    }
}
// 加载类B
public class ImageLoadServiceB {
    public void loadImage() {
        System.out.println("使用 B 加载框架");
    }
}

// 使用
public void loadNetImage(boolean useA) {
	if(useA){
		new ImageLoadServiceA().loadImage();// 使用A加载方式	
	} else {
		new ImageLoadServiceB().loadImage();// 使用B加载方式
	}
}

可以看到,上述通过一个 useA 参数判断是否使用 A 框架,为 true 使用 A,否则使用 B 框架进行加载。

使用简单工厂模式应对

但假设我们现在需要再支持一个 C 框架的使用,你可能想到了,那就再加一个 boolean 参数 useB 即可,或者直接使用一个 int 参数 loadType ,宏定义 0 代表 A 框架,1 代表 B 框架,2 代表 C 框架,这样如果需要增加方式则更新取值即可。

设计模式不过是我们写程序的招式,由于之前大家可能还学习过了简单工厂模式,我们不妨在这里进行实战。

// 抽象图片加载类 
public abstract class ImageLoadService {
    public abstract void loadImage();
}		

// 具体加载类A 
public class ImageLoadServiceA extends ImageLoadService {
    @Override
    public void loadImage() {
        System.out.println("使用 A 加载框架");
    }
}
//具体加载类B
public class ImageLoadServiceB extends ImageLoadService {
    @Override
    public void loadImage() {
        System.out.println("使用 B 加载框架");
    }
}

//具体加载类C
public class ImageLoadServiceC extends ImageLoadService {
    @Override
    public void loadImage() {
        System.out.println("使用 C 加载框架");
    }
}

public class ImageLoadFactory {
	public static ImageLoadService create(int loadType) {
	    ImageLoadService loadService = null;
	    switch (loadType) {
	        case 0:
	            loadService = new ImageLoadServiceA();
	            break;
	        case 1:
	            loadService = new ImageLoadServiceB();
	            break;
	        case 2:
	            loadService = new ImageLoadServiceC();
	            break;
	    }
	    return loadService;
	}
}

// 使用
public void loadNetImage(int loadType) {
    ImageLoadFactory.create(loadType).loadImage();
}

可以看到,我们使用简单工厂模式后,在处理新增其他加载方式的问题的时候,不会再去影响原有的加载类代码,如果新增一种加载方式的话,我们只需要新增 ImageLoadXXX 类,实现 loadImage() 加载方法,再修改工厂类 ImageLoadFactory 即可。

相信你也发现了,这个方式只能解决对象的创建问题,我们每次新增方式的时候都会新增一个类,而且需要对工厂类进行代码修改,显然是违反了开闭原则。

策略模式

人生处处有策略,上面的不同的加载方式其实就是不同的「策略」。

策略模式是对 算法的封装 ,它将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以独立变换。

策略模式的特点

  • 是一种行为模式,对算法封装,使得客户端独立于各个策略;
  • 扩展性强,添加策略无非就是添加一个具体的实现类而已,代价非常低;

策略模式的结构

zamMJb.pngbya6ny.png

策略模式做实现

要学习一个设计模式,先要学会临摹,所以上面的需求,我们可以实现为:

  1. 定义抽象策略
public interface ImageLoadStrategy {
    void loadImage() ;
}
  1. 定义具体的策略
// 具体加载类A 
public class ImageLoadStrategyA implements ImageLoadStrategy {
    @Override
    public void loadImage() {
        System.out.println("使用 A 加载框架");
    }
}
//具体加载类B
public class ImageLoadStrategyB implements ImageLoadStrategy {
    @Override
    public void loadImage() {
        System.out.println("使用 B 加载框架");
    }
}

//具体加载类C
public class ImageLoadStrategyC implements ImageLoadStrategy {
    @Override
    public void loadImage() {
        System.out.println("使用 C 加载框架");
    }
}
  1. 定义上下文,选择方式
public class ContextImageLoadStrategy {

    private ImageLoadStrategy strategy ;

    public ContextImageLoadStrategy(ImageLoadStrategy strategy){
        this.strategy = strategy ;
    }

    public void loadImage(){
        strategy.loadImage();
    }
}
  1. 使用
public void loadImage(ImageLoadStrategy imageLoadStrategy){
    ContextImageLoadStrategy contextStrategy = new ContextImageLoadStrategy(imageLoadStrategy);
    contextStrategy.loadImage();
}

注意: 策略的核心不是如何实现算法,而是如何更优雅的把这些算法组织起来,让客户端非常好调用「虽然策略非常多,可以自由切换,但是同一时间客户端只能调用一个策略,其实也很好理解,你不可能同时既坐飞机,又坐火车」。

策略模式的优点

  • 策略类可以互相替换
    由于策略类都实现同一个接口,因此他们能够互相替换。
  • 耦合度低,方便扩展
    增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合开闭原则。
  • 避免使用多重条件选择语句( if-else 或者 switch )。

策略模式的缺点

  • 策略的增多会导致子类的也会变多。比如上方再增加加载方式必须增加类。
  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。比如上方必须知道有哪些加载策略,这样我们才能调用到正确的加载方式。

你有想到如何解决「客户端必须知道所有的策略类」这个缺点么?

策略模式的应用场景

  • 同一个问题具有不同算法时,即仅仅是具体的实现细节不同时,如各种排序算法等等。
  • 对客户隐藏具体策略(算法)的实现细节,彼此完全独立;提高算法的保密性与安全性。
  • 一个类拥有很多行为,而又需要使用 if-else 或者 switch 语句来选择具体行为时。使用策略模式把这些行为独立到具体的策略类中,可以避免多重选择的结构。

源码中的策略模式

想必大家已经很清楚上面的策略模式了,下面源码中用到策略模式了吗?

  • Android 的动画插值器;
  • Android 中 ListViewArrayAdapterSimpleAdapter

写在最后

总的来说,策略模式还算我们项目开发中会使用非常频繁的模式,你学会了么?如有疑问,请在评论区留言。

#感谢您访问本站#
#本文转载自互联网,若侵权,请联系删除,谢谢!657271#qq.com#

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK