策略模式

使用封装多态实现行为型模式策略模式;

策略模式

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。

如何解决:将这些算法封装成一个一个的类,任意地替换。

关键代码:实现同一个接口。

应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

四个组成

  1.运行环境类:

    这个策略模式运行的环境,其实也就是在哪里使用,这个不需要太注意

  2.应用场景类:

    这个就是客户端访问的类,也就是该类的对象所持有的策略

  3.具体策略类:

    具体实现策略类

  4.抽象策略类:

    根据不同的需求,产生不同的策略或算法的接口

主要关注具体的实现接口的策略类 和抽象的策略接口

实现

说个例子 在日常开发中,如果一个admin在后台管理系统中设置某种用户(场景)为一个特定状态,如将某一用户设置为一等用户;那么他就在某个订单结算时优惠力度更大。也就是在结算时使用的运算将改变;

1.定义接口
1
2
3
public interface Settlement {
void SettlementDiscount(int monney);
}
2.实现接口 重写逻辑
1
2
3
4
5
6
7
8
public class PreferentiaSettlementLv1 implements   Settlement {


@Override
public void SettlementDiscount(int monney) {
System.out.println("用户需支付"+Math.ceil(monney*0.5));
}
}
1
2
3
4
5
6
7
8
public class PreferentiaSettlementLv2 implements Settlement{

@Override
public void SettlementDiscount(int monney) {
System.out.println("用户需支付"+Math.ceil(monney*0.7));
}
}

3.简单调用
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
String lv="lv1";
Settlement settlement=null;
if(lv=="lv1")
settlement=new PreferentiaSettlementLv1();
else if(lv=="lv2")
settlement=new PreferentiaSettlementLv2();
settlement.SettlementDiscount(999);

}

思考

为什么不直接在某类中写俩个处理不同等级的方法?

这样都不用这么麻烦 又是接口又是实现的。

其实直接这么做是没毛病的,但这是面向实现的编程,而不是面向接口的编程 不符合dip依赖倒置原则

策略模式的扩展

使用map的特性将代码中的if else简化

简化后:

1
2
3
4
5
6
public static void main(String[] args) {
String lv="lv1";
Settlement settlement=SettlementContext.getInstance(lv);
settlement.SettlementDiscount(999);

}
1.加入策略上下文 根据lv获得实例
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

public class SettlementContext {


public static Settlement getInstance(String lv){
Settlement inter=null;
Map<String, String> allClazz = SettlementEnum.getAllClazz();
String clazz = allClazz.get(lv);
if (lv!=null&&lv.trim().length()>0) {
try {
try {
inter = (Settlement) Class.forName(clazz).newInstance();//调用无参构造器创建实例
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return inter;
}

}

2 加入枚举 根据lv反射获得实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@AllArgsConstructor
public enum SettlementEnum {

LV1("lv1", "strategypattern.PreferentiaSettlementLv1"),
LV2("lv2", "strategypattern.PreferentiaSettlementLv2");

@Getter
@Setter
private String lv;
@Getter
@Setter
private String clazz;


public static Map<String, String> getAllClazz() {
Map<String, String> map = new HashMap<String, String>();
for (SettlementEnum sEnum : SettlementEnum.values()) {
map.put(sEnum.getLv(), sEnum.getClazz());
}
return map;
}

}

der nice