Themeplate Method
public abstract class Application {
protected abstract void init();
protected abstract void idle();
protected abstract void cleanup();
private boolean isDone = false;
protected void setDone(){
this.isDone = true;
}
protected boolean done(){
return isDone;
}
public void run(){
init();
while(!done())
idle();
cleanup();
}
}
public class WorkTemplateMethod extends Application {
public static void main(String[] args){
new WorkTemplateMethod().run();
}
@Override
protected void cleanup() {
System.out.println("clean up.");
}
@Override
protected void idle() {
System.out.println("idle.");setDone();
}
@Override
protected void init() {
System.out.println("init.");
}
}
Template Method模式展示了面向对象编程中诸多经典重用形式的一种。其中通用算法run()被放置在基类中,并且通过继承在不同的具体上下文中实现该通用算法。
但这项技术也是有代价的。继承是一种非常强的关系,派生类不可避免地要和它们的基类绑定在一起。
如果有个类Application2也需要WorkTemplateMethod中的idle()方法。然而却没法重用,由于继承了Application,就注定把WorkTemplateMethod永远地和Application绑定在了一起。
这时,我们就需要Strategy模式。
Strategy模式
public class ApplicationRunner {
private Application app = null;
public ApplicationRunner(Application app){
this.app = app;
}
public void run(){
app.init();
while(!app.done())
app.idle();
app.cleanup();
}
}
public interface Application {
public void init();
public void idle();
public void cleanup();
public boolean done();
}
public class WorkStrategy implements Application {
private boolean isDone = false;
@Override
public void cleanup() {
System.out.println("clean up.");
}
@Override
public boolean done() {
return isDone;
}
@Override
public void idle() {
System.out.println("idle.");
isDone = true;
}
@Override
public void init() {
System.out.println("init.");
}
public static void main(String[] args) {
new ApplicationRunner(new WorkStrategy()).run();
}
}
WorkStrategy对ApplicationRunner一无所知(main方法作为一个调用的例子,通常它都会在测试类中),它不依赖于run逻辑的任何实现方式。这和TemplateMethod模式是不同的,WorkTemplateMethod完全依赖于它的父类Application中run的逻辑,因而违反了DIP原则,而Strategy方法中不包含这中依赖。因此,当有别的逻辑出现时,也可以复用WorkStrategy实例中的方法。
public class ApplicationRunner2 {
private Application app = null;
public ApplicationRunner2(Application app){
this.app = app;
}
public void go(){
//app.init(); 不调用init方法
while(!app.done())
app.idle();
app.cleanup();
}
}
这样,只要使用new ApplicationRunner2(new WorkStrategy()).go()就可以了。
因此,Strategy模式比TemplateMethod模式多推荐了一个额外的好处。尽管TemplateMethod模式允许一个通用算法(run逻辑)操作多个可能的具体实现,但是由于Strategy模式完全遵循DIP原则,从而请允许每个具体实现都可以被多个不两只的通用算法(run逻辑或go逻辑)操纵。
一句话,少用继承,多用接口。