设计模式(六) — 策略模式

时势造英雄——策略模式

策略模式的定义

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

策略模式的使用场景

  • 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
  • 需要安全地封装多种同一类型的操作时。
  • 出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。

举个例子:当有一个数组,需要排序时,我们有很多排序的算法,插入排序、归并排序、冒泡排序等,一种常规的方法是将多种算法写在同一个类中,每个方法对应具体的排序算法,也可以将这些排序算法封装在一个统一的方法中,通过if…else…或者case等条件判断来选择具体的算法。这两种方式称为硬编码。然而,多个算法集中在一个类中时,这个类就会变得臃肿,维护成本变高。如果需要增加一种新的排序算法,需要修改封装算法的源代码,违反了OCP原则和单一职责原则。这时候就可以使用策略模式来解决这个问题。

策略模式的实例

现在我们来提供一个计算出行方式的费用功能。通常,我们会写成这样:

/**
 * description: 价格计算器
 */
public class PriceCalculator {
    //公交车类型
    private static final int BUS = 1;
    //地铁类型
    private static final int SUBWAY = 2;

    /**
     * description: 公交车价格计算,十公里之内一块钱,超过十公里之后每加一元钱可以乘5公里
     */
    private int busPrice(int km) {
        //超过十公里的总距离
        int extraTotal = km - 10;
        //超过的距离是五公里的倍数
        int extraFactor = extraTotal / 5;
        //超过的距离对五公里的倍数
        int fraction = extraTotal % 5;
        //价格计算
        int price = 1 + extraFactor;
        return fraction > 0 ? ++price : price;
    }

    /**
     * description: 地铁价格计算,6公里内3元,6-12公里4元,12-22公里5元,22-32公里6元,其他的都按7元算
     */
    private int subwayPrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km < 12) {
            return 4;
        }else if (km > 12 && km < 22) {
            return 5;
        }else if (km > 22 && km < 32) {
            return 6;
        }
        return 7;
    }

    /**
     * description: 供外界调用,通过type选择计算方式
     */
    int calculatePrice(int km, int type) {
        if (type == BUS) {
            return busPrice(km);
        } else if (type == SUBWAY) {
            return subwayPrice(km);
        }
        return 0;
    }
}

如果需要再向这个类中添加一个出租车的价格计算,就需要在这个类中修改代码,有可能一段代码是几个出行方式所共用的,这就容易引入错误。而且还需要在if…else…那增加出行方式,使得缠绕其中。若是再多加几种出行方式,维护起来将会很难,接下来将使用策略模式进行重构。

定义一个计算价格的抽象接口
CalculateStrategy.class

/**
 * description: 计算接口 
 */
public interface CalculateStrategy {
    /**
     * description: 按距离来计算价格
     */
    int calculatePrice(int km);
}

每种出行方式我们都有一个独立的策略类,这些策略类实现了CalculateStrategy接口。
BusStrategy.class

/**
 * description: 公交车价格计算策略
 */
public class BusStrategy implements CalculateStrategy {
    /**
     * description: 公交车价格计算,十公里之内一块钱,超过十公里之后每加一元钱可以乘5公里
     */
    @Override
    public int calculatePrice(int km) {
        //超过十公里的总距离
        int extraTotal = km - 10;
        //超过的距离是五公里的倍数
        int extraFactor = extraTotal / 5;
        //超过的距离对五公里的倍数
        int fraction = extraTotal % 5;
        //价格计算
        int price = 1 + extraFactor;
        return fraction > 0 ? ++price : price;
    }
}

SubwayStrategy.class

/**
 * description: 地铁价格计算策略
 */
public class SubwayStrategy implements CalculateStrategy {
    /**
     * description: 地铁价格计算,6公里内3元,6-12公里4元,12-22公里5元,22-32公里6元,其他的都按7元算
     */
    @Override
    public int calculatePrice(int km) {
        if (km <= 6) {
            return 3;
        } else if (km < 12) {
            return 4;
        }else if (km > 12 && km < 22) {
            return 5;
        }else if (km > 22 && km < 32) {
            return 6;
        }
        return 7;
    }
}

最后,向外提供调用的api
TranficCalculator.class

/**
 * description: 出行价格计算器
 */
public class TranficCalculator {
    CalculateStrategy calculateStrategy;

    /**
     * description: 提供给用户使用,设置具体的策略
     */
    public void setCalculateStrategy(CalculateStrategy calculateStrategy) {
        this.calculateStrategy = calculateStrategy;
    }

    /**
     * description: 设置策略后,调用计算价格
     */
    public int calculatePrice(int km) {
        return calculateStrategy.calculatePrice(km);
    }
}

小结

优点

  • 结构清晰明了,使用简单直观。
  • 耦合度相对而言较低,扩展方便。
  • 操作封装也更为彻底,数据更为安全。

缺点

随着策略的增加,子类也会变得繁多。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值