Android设计模式-策略模式

Posted vanpersie_9987

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android设计模式-策略模式相关的知识,希望对你有一定的参考价值。

策略模式介绍

考虑这样一种情况:实现某个功能可以有多种算法或者策略,我们根据实际情况选择不同的算法或者策略来完成该功能。如,排序算法,可以使用插入排序、归并排序、冒泡排序等。

针对这样的情况,一种常规方法是将多种算法写在一个类中。如,需要提供多种排序算法,可以将这些算法写到一个类中,每一个方法对应一个具体的方法;当然,也可以将这些排序算法封装到一个统一的方法中,通过if…else 或者case等条件判断语句来选择具体的算法。这两种实现方法我们都可以称为硬编码。然而,当很多算法集中在一个类时,这个泪就会变得臃肿,这个类的维护成本就会变高,在维护时也更容易引发错误。如果我们需要增加一种新的排序算法,就需要修改封装算法类的源代码,这违反了OCP原则和单一职责原则(设计模式六大原则)。

如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或者策略有不同的实现类,这样在程序客户端就可以通过注入不同的实现对象来实现算法或者策略的动态替换,这种模式的可扩展性、可维护性更高,这就是策略模式。

定义

策略模式定义了一系列算法,并将每一个算法封装起来,而且使它们可以相互替换。策略模式让算法独立于使用它们的客户而独立变化。

策略模式的使用场景

  • 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。

  • 需要安全地封装多种同一类型的操作时。

  • 出现统一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。

策略模式的简单实现

举一个简单的例子:北京的公交是分段计价,显然,公交车和地铁的价格计算方式是不一样的,但是我们的示例中是需要计算乘不同出行工具的成本,下面是第一个版本:

public class PriceCalculator 
    //公交车类型
    private static final int BUS = 1;
    //地铁类型
    private static final int SUBWAY = 2;
    public static void main(String[] args) 
        PriceCalculator  calculator = new PRiceCalculator();
        System.out.println("坐16公里的公交车票价为:" + calculator.calculatePrice(16, BUS));
        System.out.println("坐16公里的地铁票价为:" + calculator.calculatePrice(16, SUBWAY));
    
    //北京公交车,10公里之内一元,超过十公里后每加一元可以乘5公里
    // @param km 公里
    // @return
    private int busPrice(int km) 
        //超过十公里的总距离
        int extraTotal = km - 10;
        //超过的距离时5公里的倍数
        int extraFactor = extraTotal / 5;
        //超过的距离对5公里取余;
        int fraction = extraTotal % 5;
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price; 
    
    //6公里(含)内3元;6-12公里(含)4元;12-22公里(含)5元;22-32公里(含)6元
    // @param km 公里
    // @return
    private int subwayPrice(int km) 
        if(km <= 6) 
            return 3;

         else if(km > 6 && km <= 12) 
            return 4;
         else if(km > 12 && km <= 22) 
            return 5;

         else if(km > 22 && km <= 32) 
            return 6
         
        return 7;
    
    int calculatePrice(int km, int type) 
        if(type == BUS) 
            return busPrice(km);
         else if(type == SUBWAY) 
            return subwayPrice(km);
        
        return 0;
    

PriceCalculator类很明显的问题就是并不是单一职责,因为它同时承担了公交票价和地铁票价的计算任务;另外,使用if-else的形式判断计算结果,这种方式的扩展性不高,如果增加一种出租车的出行方式,那么就需要添加一个方法来计算出租车的价格,并且在calculatePrice(int km, int type)函数中增加一个判断。

所以我们需要使用策略模式进行重构,这里命名为CalculateStrategy,具体为:

//计算接口
public interface CalculateStrategy 
    //按距离来计算价格
    // @param km 公里
    // @return 返回价格
    int calculatePrice(int km);


对于每一种出行方式都有一个独立的策略类,这些策略类都实现了CalculateStrategy接口:

//公交车价格的计算策略
public class BusStrategy implements CalculateStrategy 
    // @param km 公里
    // @return 
    @Override
    public int calculatePrice(int km) 
        //超过十公里的总距离
        int extraTotal = km - 10;
        //超过的距离时5公里的倍数
        int extraFactor = extraTotal / 5;
        //超过的距离对5公里取余;
        int fraction = extraTotal % 5;
        int price = 1 + extraFactor * 1;
        return fraction > 0 ? ++price : price; 
    
//地铁价格计算策略
public class SubwayStrategy implements CalculateStrategy 
    @Override
    public int calculatePrice(int km) 
    if(km <= 6) 
            return 3;

         else if(km > 6 && km <= 12) 
            return 4;
         else if(km > 12 && km <= 22) 
            return 5;

         else if(km > 22 && km <= 32) 
            return 6
         
        return 7;



    

再创建一个扮演Context角色的类:

public class TranficCalculator 
    public static void main(String[] args) 
        TranficCalculator calculator = new TranficCalculator();
        //设置计算策略
        calculator.setStrategy(new BusStrategy());
        //计算价格
        /Sysyem.out.println("公交车乘16公里的价格:" + calculaor.calculatePrice(16));
    


    CalculateStrategy mStrategy;
    public void setStrategy(CalculateStrategy mStrategy) 
        this.mStrategy = mStrategy;
    
    public int calculatePrice(int km) 
        return mStrategy.calculatePrice(km);
    

这种方式在隐藏实现的同时,可扩展性变得更强,如需增加出租车的计价策略,只需添加一个出租车计算策略类,然后将该策略设置给TranficCalculator:

//出租车计价策略

public class TaxiStrategy implemtents CalculateStrategy 
    //价格我们简单计算为公里数 * 2
    @Override
    public int calculatePrice(int km) 
        return km * 2;
    

将策略注入到TranficCalculator中:

... ...
... ...
calculator.setStrategy(new TaxiStrategy());
... ...
... ...

通过上述示例可以看出,通过建立抽象,将不同的策略简称一个具体的策略实现,通过不同的策略实现算法替换,在简化逻辑,结构的同时,增强了系统的可读性、稳定性、可扩展性,这对于较为复杂的业务逻辑显得更为直观,扩展也更为方便。

策略模式的应用实战

下面举一个栗子,主要功能是为ImageLoader添加一个顺序和逆序的图片加载策略。

//加载策略接口
public interface LoadPolicy 
    int compare(BitmapRequest request, BitmapRequest request2);


//顺序加载
public class SerialPolicy implements LoadPolicy 
    @Override
    public int compare(BitmapRequest request, BitmapRequest request2) 
        return request1.serialNum - request2.serialNum;
    



//逆序加载
public class ReversePolicy implements LoadPolicy 
    @Override
    public int compare(BitmapRequest request, BitmapRequest request2) 
        // 注意, Bitmap请求要求先执行最晚加入队列的请求,ImageLoader的策略
        return request2.serialNum - request1.serialNum;
    

首先定义了一个LoadPolicy接口,在这个接口中有一个compare方法,用来对比两个请求,分别为顺序加载、逆序加载两个策略,因为每一个请求都有一个序列号,这个序列号以递增的形式增长,越晚加入队列的请求的序列号越大,而我们的请求队列是优先级队列,所以需要实现Comparable接口,以实现排序:

public class BitmapRequest implements Comparable<BitmapRequest> 
    //加载策略
    LoadPolicy mLoadPolicy = new SerialPolicy();
    @Override
    public  int compareTo(BitmapRequest another) 
        //委托给LoadPolicy进行处理
        return mLoadPolicy.compare(this, another);
    

在客户端请求时,用户再配置ImageLoader时可以设置加载策略,
这个策略会被设置给每个图片加载请求对象,具体代码:

public void displayImage(final ImageView imageView, final String uri, final DisplayComfig config, final ImageListener listener) 
    BitmapRequest request = new BitmapRequest(imageView, uri, config, listener);
    //加载的配置兑现,如果没有设置则使用ImageLoader的配置
    request.displayConfig = request.displayConfig != null ? request.displayConfig : mConfig.displayConfig;


    //设置加载策略
    request.setLoadPolicy(mConfig.loadPolicy);
    //添加到队列中
    mImageQueue.addRequest(resuest);

总结

策略模式主要用于分离算法,在相同的行为抽象下有不同的实现策略,这个模式很好地演示了开闭原则,也就是定义抽象,注入不同的实现,从而达到很好的可扩展性。

  • 优点:

(1)接口清晰明了、使用简单。

(2)耦合性相对较低,扩展方便;

(3)操作封装也更为彻底,数据更为安全。

  • 缺点:

随着策略的增加,子类汇变得更多。

以上是关于Android设计模式-策略模式的主要内容,如果未能解决你的问题,请参考以下文章

粗糙分析设计模式-策略模式

《Android源码设计模式》--策略模式

23种设计模式---策略设计模式

Android 设计模式 笔记 - 策略模式

设计模式与Android状态模式——一个人的两幅面孔

简说设计模式——策略模式