策略模式

策略模式

  策略模式(Strategy),定义了算法家族,分别封装起来,让各个算法可以互相替换,使算法的变化不会影响到使用算法的用户。

  从概念来看,不同算法的区别只是实现不同,但目标是一致的,那么可以以相同的方式来调用所有的方法,从而减少了各种算法类与调用者之间的耦合。还有一个优点是,因为每个算法都有自己的类,从而简化了单元测试。

  将判断语句从使用者中移除,即封装了变化,无论是算法还是各种规则和流程,就都可以考虑利用策略模式来实现。

  以下为策略模式的基本结构。

策略模式结构图

3.8.x 案例

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class Test {
public static void main(String[] args) {
//实现根据客户所购买商品的单价和数量对客户收费
System.out.println("--------------------1.直接核算");
double total = 0.0;
//获取界面商品价格
String textPrice = "2.5";
//获取界面商品数目
String txtNum = "300";
//计算总价格
double totalPrices = btnOk_click(textPrice,txtNum);
total += totalPrices;
System.out.println("单价:" + textPrice + ",数量:" + txtNum);
System.out.println(" 合计:" + totalPrices);


//新增需求要对商品打折
System.out.println("--------------------2.新增打折策略");
//选择打折策略
String type = form1_load().get(3);
//计算总价格
double totalPrices_discount = btnOk_click_discount(textPrice,txtNum,type);
System.out.println("单价:" + textPrice + ",数量:" + txtNum+ ",打折策略:" + type);
System.out.println(" 合计:" + totalPrices_discount);
}

//点击OK按钮,获取当前商品总价格
private static double btnOk_click(String textPrice, String txtNum){
return Double.parseDouble(textPrice) * Double.parseDouble(txtNum);
}


//点击打折策略,获取可选策略
private static List<String> form1_load(){
return Arrays.asList("正常价格","八折","七折","六折");
}

private static double btnOk_click_discount(String textPrice, String txtNum, String type){
double discount_parm = 0.0;
switch (type){
case "正常价格":
discount_parm = 1.0;
break;
case "八折":
discount_parm = 0.8;
break;
case "七折":
discount_parm = 0.7;
break;
case "六折":
discount_parm = 0.6;
break;
}
return Double.parseDouble(textPrice) * Double.parseDouble(txtNum) * discount_parm;
}
}
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    public static void main(String[] args) {
......

//根据简单工厂模式改写
System.out.println("--------------------3.简单工厂模式实现");
//实现内容于Example1
List<String> types = Arrays.asList("正常收费","满300返100","八折");
System.out.println("单价:" + textPrice + ",数量:" + txtNum);
double totalPrices_example1 = btnOk_click(textPrice,txtNum);
for(String type_example1 : types){
Charging charging = ChargingFactory.createCharging(type_example1);
System.out.println("策略:" + type_example1);
double totalPrices_value_example1 = charging.charge(totalPrices_example1);
System.out.println(" 合计:" + totalPrices_value_example1);
}
//简单工厂模式只是解决了对象创建的变更问题,而对于打折力度和返利条件这些变更却无法应对
}

public abstract class Charging {
public abstract double charge(double money);
}

public class NormalCharging extends Charging{
@Override
public double charge(double money) {
return money;
}
}

public class DiscountCharging extends Charging {
private double rebate;

public DiscountCharging(double rebate) {
this.rebate = rebate;
}

@Override
public double charge(double money) {
return money * rebate;
}
}

public class CashReturnCharging extends Charging {
private double condition;//返利条件
private double returnValue;//返利金额

public CashReturnCharging(double condition, double returnValue) {
this.condition = condition;
this.returnValue = returnValue;
}

@Override
public double charge(double money) {
if(money >= condition)
return money - Math.floor(money / condition) * returnValue;
else
return money;
}
}

public class ChargingFactory {
public static Charging createCharging(String type){
Charging charging = null;
switch (type){
case "正常收费":
charging = new NormalCharging();
break;
case "满300返100":
charging = new CashReturnCharging(300,100);
break;
case "八折":
charging = new DiscountCharging(0.8);
break;
}
return charging;
}
}
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    public static void main(String[] args) {
......
//策略模式结构参考包Struct
System.out.println("--------------------4.策略模式实现");
//实现内容于Example2
List<String> types_example2 = Arrays.asList("正常收费","满300返100","八折");
System.out.println("单价:" + textPrice + ",数量:" + txtNum);
double totalPrices_example2 = btnOk_click(textPrice,txtNum);
for(String type_example2 : types_example2){
CashContextRevision context = new CashContextRevision(type_example2);//和简单工厂模式的区别在消除了客户端和实现算法的耦合,只须关注context
System.out.println("策略:" + type_example2);
double totalPrices_value_example2 = context.getResult(totalPrices_example2);
System.out.println(" 合计:" + totalPrices_value_example2);
}
}

//根据策略模式实现,可以通过将switch模块转移到Context构造器实现选择具体策略由客户端控制转移到Context控制,即结合了策略和工厂模式
private static double btnOk_click_strategy(String textPrice, String txtNum, String type){
CashContext context = null;
switch (type){
case "正常收费":
context = new CashContext(new NormalCharging());
break;
case "满300返100":
context = new CashContext(new CashReturnCharging(300,100));
break;
case "八折":
context = new CashContext(new DiscountCharging(0.8));
break;
}
return context.getResult(Double.parseDouble(textPrice) * Double.parseDouble(txtNum));
}

public class CashContext {
private Charging charging;

public CashContext(Charging charging) {
this.charging = charging;
}

public double getResult(double money){
return charging.charge(money);
}
}

public class CashContextRevision {
private Charging charging;

public CashContextRevision(String type) {
switch (type){
case "正常收费":
this.charging = new NormalCharging();
break;
case "满300返100":
this.charging = new CashReturnCharging(300,100);
break;
case "八折":
this.charging = new DiscountCharging(0.8);
break;
}
}

public double getResult(double money){
return charging.charge(money);
}
}

3.8.x 代码结构

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
43
44
45
46
47
48
49
50
51
52
53
54
//抽象算法类
public abstract class Strategy {

//算法方法
public abstract void AlgorithmInterface();
}

//具体算法A
public class ConcreteStrategyA extends Strategy {

@Override
public void AlgorithmInterface() {
System.out.println("算法A实现");
}
}

public class ConcreteStrategyB extends Strategy {

@Override
public void AlgorithmInterface() {
System.out.println("算法B实现");
}
}

......

//上下文
public class Context {
Strategy strategy;

//初始化时传入策略对象
public Context(Strategy strategy) {
this.strategy = strategy;
}

//根据具体的策略对象,调用其算法
public void ContextInterface(){
strategy.AlgorithmInterface();
}
}

//客户端
public class Main {

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();
}
}

参考:

🔗 《设计模式:可复用面向对象软件的基础》

🔗 《大话设计模式》