策略模式
策略模式可以定义为,定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
基于一个简单的例子来看一下,假设我们明天中午吃饭有三种选择,泡面,订外卖,煮饺子。要做选择可以这么做
首先定义一个接口
interface Lunch{
public void eat();
}
具体的实现类如下
public class InstantNoodle implements Lunch{
public void eat(){
//eat InstantNoodle;
}
}
public class TakeAway implements Lunch{
public void eat(){
//eat takeaway;
}
}
public class Dumplings implements Lunch{
public void eat(){
//eat dumplings;
}
}
其实这时候而言,我们的功能已经算完成了。为了保证选择的封装性,便捷切换以及良好的扩展性,我们可以为他增加一个封装类,在策略模式中通常叫做Context。
public class Context{
private Lunch lunch = null;
public Context(Lunch lunch){
this.lunch = lunch;
}
private void toEat(){
lunch.eat();
}
}
这时候如果第二天我选择我要吃的东西就可以使用如下方式:
public class Main{
public static void main(String[] args) {
//想吃泡面
Context context = Context(new InstantNoodle());
context.eat();
}
}
对于策略模式而言,我们可以使用如下的类图来进行表示:
策略模式
优势与缺点
优点
- 算法可以自由的切换
- 避免多重条件的判断
- 扩展性好
缺点
- 策略种类多
- 策略类需要对外暴漏
应用场景
在JDK中的ThreadPoolExecutor使用了策略模式,它预定了4中策略:
ThreadPoolExecutor.AbortPolicy()
ThreadPoolExecutor.CallerRunsPolicy()
ThreadPoolExecutor.DiscardOldestPolicy()
ThreadPoolExecutor.DiscardPolicy()
可以看到每个策略都被放在一个单独的类中
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
工厂模式
这里不再举例实际的工厂例子,实际的例子可以参照我的这篇文章。
特征和优缺点
我们知道工厂模式可以分为简单工厂模式,工厂方法模式和抽象工厂模式,我们简单来讨论下他们的特点和优缺点。
简单工厂模式
优点是比较简单,简化了类的创建过程。
缺点是工厂类的扩展比较困难,不符合开闭原则。
工厂方法模式
工厂方法模式是典型的解耦框架,在new一个对象的地方可以替换,所以在所有需要生成对象的地方都可以使用。
使用案例
1.如果使用JDBC连接数据库,数据库从MySQL切换到Oracle,需要改动的地方就是切换一下驱动名称(前提条件是SQL语句是标准语句),其他的都不需要修改,这是工厂方法模式灵活性的一个直接案例。
2.在实际的单元测试应用中,如果要测试一下代码
Class TestA{
public int test(){
DoSomeThing dst = new DoSomeThing();
dst.run();
}
}
因为方法体创建的对象使用一般的Mockito是不能进行mock的,这时候我们可以构造一个工厂方法。
Class Factory{
public DoSomeThing build(){
return new DoSomeThing ();
}
}
新的代码可以写为
Class TestB{
Factory factory = new Factory();
public int test(){
DoSomeThing s = factory.build();
s.run();
}
}
这样便可以进行mock,顺利完成单元测试。
抽象工厂方法
抽象工厂抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
抽象工厂方法的优势
- 封装性
- 产品族内的约束为非公开状态
应用场景
例如一个应用,需要在三个不同平台(Windows、Linux、Android),通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。
网友评论