源码地址 | https://github.com/DingMouRen/DesignPattern |
---|
- Context------用来操作策略的对象
- Stragety------策略的抽象
- ConcreteStragetyA、ConcreteStragetyB ------具体策略的实现
定义
策略模式定义一系列的算法,把它们一个个封装起来 , 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
使用场景
- 许多相关的类仅仅是具体实现不同。
- 处理同一个问题,但是有不同的算法实现。
- 一个类定义了多种行为,并且这些行为在这个类的操作中会以if-else或者switch-case的形式出现时。
协作
- Strategy与Context相互作用来实现选定的算法。当算法被调用时,Context可以将该算法所需要的所有数据都传递给该Strategy。或者,Context可以将自身作为一个参数传递给Strategy操作。这就让Strategy在需要时可以回调Context
- Context将它的客户的请求转发给它的Strategy。客户通常创建并传递一个ConcreteStrategy对象给该Context,这样客户端仅需要与Context交互。通常有一系列的ConcreteStrategy类可供客户端从中选择。
举个栗子
一个学生要获取到数字6,他有多种算法。
一般做法:假设在类Student中实现获取到数字6的算法getNumberSix(),如果老师要求使用相加的方式来实现,那么我们就用相加的方式来实现;没多久老师又让我们用相乘的方式来实现,好吧,我们再写相乘方式的算法;又没多久老师让我再以相减的方式来实现,我们又得回到Student类添加if-else,又对代码进行修改,违背了OO的开闭原则,设计的类应该是对扩展开放,对修改关闭。
//获取到数字6
public void getNumberSix(String str){
if (str.equals("相加")){
addMethod();//相加的方式获取到数字6
}else if (str.equals("相乘")){
multiMethod();//相乘的方式获取到数字6
}else if (str.equals("相减")){
subtractMethod();//通过相减的方式获取到数字6
}
}
思考:我们想让Student类一旦编写结束,尽量不要再修改它,获取到数字6的算法有多种,怎么办呢?考虑到java的封装与多态,我们可以将算法封装成一个类,再向上抽象,抽象成一个接口,这个接口有一个方法(获取数字6的算法),每一个实现类都要实现这个方法。我们通过聚合的方式,将接口通过类Student的构造函数作为一个成员变量置于Student类中,在Student类的getNumberSix()方法中调用接口的方法。接口实现类负责具体算法的实现,比如相加获取6,相乘获取6,Studnet类要获取数字6的话,就在创建Student时传入接口实现类,java多态自动向上转型,传入的类型都是接口类型的,然后在调用getNumberSix()时,java的向下转型和运行时类型判断就起到了关键作用,这时调用的方法就是当时传入的接口实现类的方法。如果老师还想要其他的算法要求的话,只要实现接口的方法,传入新的算法就行了,这样就非常容易扩展了,也不用修改Student类。为了可以动态的更换算法,我们添加一个set方法,就可以实现动态更换算法了。
//学生
public class Student {
private Stragety stragety;//策略的抽象,也可以称作泛化
public Student(Stragety stragety) {
this.stragety = stragety;
}
/**
* 获取数字6
*/
public void getNumberSix(){
int result = stragety.calculate();
System.out.println(result == 6 ? "获取的数字正确":"获取的数字不正确,获取到的数字是"+result);
}
/**
* 可以动态的更换策略
* @param stragety
*/
public void setStragety(Stragety stragety) {
this.stragety = stragety;
}
}
//策略的抽象
public interface Stragety {
int calculate();//获取到数字6的方法抽象
}
//具体策略的实现:相加
public class StragetyAdd implements Stragety {
/**
* 具体算法的实现:通过相加的方式获取到数字6
* @return
*/
@Override
public int calculate() {
int result = 0;
for (int i = 0; i < 6; i++) {
result += 1;
}
return result;
}
}
//具体策略的实现:相乘的
public class StargetyMultiply implements Stragety{
/**
* 具体算法的实现:通过相乘的方式获取到数字6
* @return
*/
@Override
public int calculate() {
int result = 2 * 3;
return result;
}
}
使用
public static void main(String[] args) {
//创建对象
Student student = new Student(new StragetyAdd());
//获取到数字6
student.getNumberSix();
//动态更换策略
student.setStragety(new StargetyMultiply());
student.getNumberSix();
}
总结
优点
- 结构清晰,使用简单
- 耦合度相对较低
- 扩展方便
- 操作封装后,数据更加安全
缺点 - 随着策略的增加,子类会变得繁多
网友评论