1.什么是策略模式
在实际开发过程中,实现某一功能可能会有多种算法,例如常用的排序算法就有插入排序 、选择排序、交换排序、归并排序等。有些场景下,系统需要根据输入条件以及运行环境选择不同的算法来完成某一功能,开发人员可以通过硬编码的方式将多种算法通过条件分支语句写到一个类中,但这显然是不符合“开放封闭”原则的,当需要添加新的算法时,只能修改这个类的代码,破坏了这个类的稳定性。而且,将大量的复杂算法堆放到一起,代码看起来也会比较复杂 ,不易维护 。
为了解决上述问题,可以考虑使用策略模式。策略模式中定义了 一系列算法,将每一个算法封装起来,由不同的类进行管理,并让它们之间可以相互替换 。 这样,每种算法都可以独立地变化。
策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某个问题,同时方便地更换算法或者增加新的算法,并且由客户端决定调用哪个算法。 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
例子:针对老用户大量,新用户大量,老用户少量,新用户少量,进行不同程度的打折。这时候就分别定义四种情况的打折幅度,类中的内容也非常简洁,然后通过context来统一管理,统一调用。
定义接口,getPrice是各个实体类都要实现的接口,context也实现类这个方法,但是是交给构造出的
Strategy对象来执行:
public interface Strategy {
public double getPrice(double standerdPrice);
}
定义四种实现类:
public class NewCustmoerFewStrategy implements Strategy {
@Override
public double getPrice(double standerdPrice) {
System.out.println("打9折");
return standerdPrice * 0.9;
}
}
public class OldCustmoerlargeStrategy implements Strategy {
@Override
public double getPrice(double standerdPrice) {
System.out.println("打5折");
return standerdPrice * 0.5;
}
}
public class OldCustmoerFewStrategy implements Strategy {
@Override
public double getPrice(double standerdPrice) {
System.out.println("打8折");
return standerdPrice * 0.8;
}
}
public class NewCustmoerlargeStrategy implements Strategy {
@Override
public double getPrice(double standerdPrice) {
System.out.println("打6折");
return standerdPrice * 0.6;
}
}
实现上下文类:
public class Context {
/**
* 负责和具体的策略类交互
* 这样就实现了具体算法和直接客户端之间的分离了,是的算法可以独立与客户端独立地变化。
* 如果使用spring的依赖注入功能,还可以通过配置文件,动态的注入不同的策略对象,动态地切换不同的算法。
*/
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void printPrice(double s) {
System.out.println("该给的报价为:" + strategy.getPrice(s));
}
}
调用:
public static void main(String[] args) {
Strategy strategy = new NewCustmoerFewStrategy();
Context context = new Context(strategy);
context.printPrice(1000);
}
本质:
分离算法,选择实现。
策略模式与委派模式的区别:委派是将一个大任务拆分成小任务,分别执行,上层只关心结果,而不关心谁干的。而策略模式是从多个方法中选择一个来进行。
2.策略模式在SqlSession 中的应用
从开始到现在为止,所有的示例中使用的 Sq!Session 对象实现都是 DefaultSqlSession类型,它也是单独使用 MyBatis 进行开发时最常用的 SqISession 接口实现。
在 DefaultSq!Session 中使用到了策略模式, DefaultSq!Session 扮演了 Context 的角色,而将所有数据库相关的操作全部封装到 Executor 接口实现中,并通过 executor 字段选择不同的Executor 实现。
DefaultSq!Session 中实现了 SqISession 接口中 定义的方法 , 并且为每种数据库操作提供了多个重载 。下图为select()方法、 selectOne()方法、 selectList()方法以及 selectMap()方法的各个重载方法之间的调用关系。
上述重载方法最终都是通过调用 Executor.query(MappedStatement, Object, RowBounds,ResultHandler)方法实现数据库查询操作的,但各自对结果对象进行 了 相 应 的调 整 , 例如selectOne()方法是从结果对象集合中获取了第一个元素返回: selectMap ()方法会将 List 类型的结果对象集合转换成 Map 类型集合返回: select()方法是将 结果对 象集合交 由用 户 指定的ResultHandler 对象处理,且没有返回值: selectList()方法则 是直接返回 结果对象集合。
DefaultSqlSession.insert()方法、 update()方法、 delete()方法也有多个重载,它们最后都是通过调用的 DefaultSqlSession.update(String, Object)方法实现的,该重载首先会:|夺 dirty 字段置为 true,
然后再通过 Executor.update()方法完成数据库修改操作 。 代码比较简单,就不再展示了。
DefaultSqlSession.commit()方法、 rollback()方法以及 close()方法都会调用 Executor 中相应的
方法,其中就会涉及清空缓存的操作, 之后就会将 dirty字段设置为 false 。