您的位置:首页 > 其它

设计模式-策略模式

2017-09-22 10:45 239 查看

定义

策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

结构

策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。下面就以一个示意性的实现讲解策略模式实例的结构。

测试模式涉及到的三个角色:

  ●  策略容器(Context):持有一个Strategy的引用,可以在构造方法中注入这个策略的对象,把调用处(客户端)和策略的实现管理起来。

  ●  策略(Strategy)接口:策略接口通常给出所有的具体策略类所需的接口,定义一个标准接口,供具体的算法实现类去实现以及供策略容器对象持有。

  ●  具体策略(ConcreteStrategy)角色:包装了相关的算法或行为,实现了策略接口。

实际案例分析

在做企业对公理财项目中,有三种购买理财产品的方式:a)固定金额,b)固定比例,c)固定剩余,所以,在扣款的时候,要根据用户的购买方式和用户的账户余额去计算本次用户实际要购买的金额。(这里只是讨论用策略模式去实现根据不同购买类型计算出相应的购买金额,不去讨论是否大于起头金额,是否满足递增等业务逻辑了)。

最初的写法(T1-1程序员)

if (购买方式 == 固定金额) {
去检查账户余额是否 >= 购买金额;
return 实际的购买金额;
} else if (购买方式 == 固定比例) {
检查账户余额, 计算实际购买金额;
return 实际的购买金额;
} else if (购买方式 == 固定剩余) {
检查账户余额, 计算实际购买金额;
return 实际购买金额;
}


这里只是写了去计算的代码,实际的业务比这复杂很多的,导致整个方法太过大了,代码已经很难阅读了。

现在用策略模式去改造(T2-1程序员):

定义一个策略接口,去计算本次预约金额:

“`

public interface CalculateBookingMoneyService {

BigDecimal calculate(BigDecimal accountBalance);

}

2.根据不同的计算方式,写不同的计算实现:


@Service

public class FixedAmountStrategy implements CalculateBookingMoneyService {

Logger logger = LoggerFactory.getLogger(FixedAmountStrategy.class);

@Override
public BigDecimal calculate(BigDecimal accountBalance) {
logger.info("开始固定金额的计算方式...");
return accountBalance;
}


}

@Service

public class FixedRateStrategy implements CalculateBookingMoneyService {

Logger logger = LoggerFactory.getLogger(FixedRateStrategy.class);

@Override
public BigDecimal calculate(BigDecimal accountBalance) {
logger.info("开始固定比例的预约方式...");

return accountBalance.multiply(new BigDecimal("0.5")).setScale(2, BigDecimal.ROUND_DOWN);
}


}

@Service

public class FixedRemainStrategy implements CalculateBookingMoneyService {

Logger logger = LoggerFactory.getLogger(FixedRemainStrategy.class);

@Override
public BigDecimal calculate(BigDecimal accountBalance) {
logger.info("开始留存金额的计算方式...");
return accountBalance.subtract(BigDecimal.TEN).setScale(2, BigDecimal.ROUND_DOWN);
}


}

3.创建一个计算方式的持有对象:


@Setter

@Getter

public class CalculateMoney {

private CalculateBookingMoneyService calculateBookingMoneyService;

public CalculateMoney(CalculateBookingMoneyService param) {
this.calculateBookingMoneyService = param;
}

public BigDecimal calculate(BigDecimal bigDecimal) {
return this.calculateBookingMoneyService.calculate(bigDecimal);
}


}

4.客户端测试:


@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration({“classpath:spring/spring-mvc.xml”})

public class TestStrategyFactory {

@Test

public void TestStrategy() {

CalculateBookingMoneyService amountStrategy = new FixedAmountStrategy();

CalculateBookingMoneyService rateStrategy = new FixedRateStrategy();

CalculateBookingMoneyService remainStrategy = new FixedRemainStrategy();

CalculateMoney amountStrategyResult = new CalculateMoney(amountStrategy);

CalculateMoney remainStrategyResult = new CalculateMoney(remainStrategy);

CalculateMoney rateStrategyResult = new CalculateMoney(rateStrategy);

BigDecimal result = amountStrategyResult.calculate(new BigDecimal(“1000”));

BigDecimal result2 = remainStrategyResult.calculate(new BigDecimal(“1000”));

BigDecimal result3 = rateStrategyResult.calculate(new BigDecimal(“1000”));

System.out.println(result);

System.out.println(result2);

System.out.println(result3);

}

}

5.输出结果:


[2017-09-22 10:10:47.055] INFO [main] FixedAmountStrategy.java:26 - 开始固定金额的计算方式…

[2017-09-22 10:10:47.056] INFO [main] FixedRemainStrategy.java:23 - 开始留存金额的计算方式…

[2017-09-22 10:10:47.056] INFO [main] FixedRateStrategy.java:23 - 开始固定比例的预约方式…

1000

990.00

500.00

“`

策略模式的优点

  (1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。

  (2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

策略模式的缺点

  (1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。

  (2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息