学习设计模式——策略模式

概述

策略模式:(Strategy Design Pattern)定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。

策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。

何时使用:

  • 一个系统有许多许多类,而区分它们的只是他们直接的行为。

UML 类图:

image.png

角色组成:

  1. Context上下文: 也叫Context封装角色,起承上启下的作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。
  2. 抽象策略角色:抽象策略角色,是对策略、算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性。
  3. 具体策略角色: 用于实现抽象策略中的操作,即实现具体的算法。

通用代码

Context上下文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码public class Context {

private Strategy strategy;

public Context(Strategy strategy) {
this.strategy = strategy;
}

// 上下文接口
public void contextInterface() {
strategy.algorithmInterface();
}

}

抽象策略角色:

1
2
3
4
5
6
java复制代码public interface Strategy {

// 算法方法
void algorithmInterface();

}

具体策略角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码public class ConcreteStrategyA implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法A实现");
}
}


public class ConcreteStrategyB implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法B实现");
}
}


public class ConcreteStrategyC implements Strategy {
@Override
public void algorithmInterface() {
System.out.println("算法C实现");
}
}

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码public class Test {
public static void main(String[] args) {

Context context;

context = new Context(new ConcreteStrategyA());
context.contextInterface();

context = new Context(new ConcreteStrategyB());
context.contextInterface();

context = new Context(new ConcreteStrategyC());
context.contextInterface();

}
}

结果:

算法A实现

算法B实现

算法C实现

如何利用策略模式避免分支判断

看这样一个案例:给不同的订单不同的折扣策略。不使用策略模式时,我们是这样写代码的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
java复制代码public class OrderService {
public double discount(Order order) {
double discount = 0.0;
OrderType type = order.getType();
if (type.equals(OrderType.NORMAL)) { // 普通订单
// 省略折扣计算算法代码
} else if (type.equals(OrderType.GROUPON)) { // 团购订单
// 省略折扣计算算法代码
} else if (type.equals(OrderType.PROMOTION)) { // 促销订单
// 省略折扣计算算法代码
}
return discount;
}
}


public enum OrderType {

NORMAL, // 普通订单

GROUPON, // 团购订单

PROMOTION // 促销订单

}


public class Order {
OrderType type;

public Order(OrderType type) {
this.type = type;
}

public OrderType getType() {
return type;
}

public void setType(OrderType type) {
this.type = type;
}
}

如何来移除掉分支判断逻辑呢?那策略模式就派上用场了。我们使用策略模式对上面的代码重构,将不同类型订单的打折策略设计成策略类,并由工厂类来负责创建策略对象。具体的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
java复制代码public interface DiscountStrategy {

double calDiscount(Order order);

}


public class NormalDiscountStrategy implements DiscountStrategy {
@Override
public double calDiscount(Order order) {
System.out.println("经过计算,该订单不打折!");
return 1;
}
}


public class GrouponDiscountStrategy implements DiscountStrategy {
@Override
public double calDiscount(Order order) {
System.out.println("经过计算,该订单打八折!");
return 0.8;
}
}


public class PromotionDiscountStrategy implements DiscountStrategy {
@Override
public double calDiscount(Order order) {
System.out.println("经过计算,该订单打七折!");
return 0.7;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码public class DiscountStrategyFactory {
private static final Map<OrderType, DiscountStrategy> strategies = new HashMap<>();

static {
strategies.put(OrderType.NORMAL, new NormalDiscountStrategy());
strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());
strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());
}

public static DiscountStrategy getDiscountStrategy(OrderType type) {
return strategies.get(type);
}
}
1
2
3
4
5
6
7
java复制代码public class OrderService {
public double discount(Order order) {
OrderType type = order.getType();
DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type);
return discountStrategy.calDiscount(order);
}
}

测试:

1
2
3
4
5
6
7
8
java复制代码public class Test {
public static void main(String[] args) {
OrderService orderService = new OrderService();
orderService.discount(new Order(OrderType.NORMAL));
orderService.discount(new Order(OrderType.GROUPON));
orderService.discount(new Order(OrderType.PROMOTION));
}
}

测试结果:

经过计算,该订单不打折!

经过计算,该订单打八折!

经过计算,该订单打七折!

测试用例的两种写法结果都是一样的

总结

策略模式定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。

策略模式用来解耦策略的定义、创建、使用。实际上,一个完整的策略模式就是由这三个部分组成的。

  • 策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。
  • 策略的创建由工厂类来完成,封装策略创建的细节。
  • 策略模式包含一组策略可选,客户端代码如何选择使用哪个策略,有两种确定方法:编译时静态确定和运行时动态确定。其中,“运行时动态确定”才是策略模式最典型的应用场景。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%