(九)模板方法模式详解(包含与类加载器不得不说的故事) (二)

2014-11-24 10:41:11 · 作者: · 浏览: 2
我们简单的加入一个head和body标签,然后创建测试类运行一下,就会发现,我们按照父类给的标准模板,生成了一个html页面。

这样做的方式的好处是,父类可以规范子类的创建过程,便于我们维护,而且子类也更省事,因为像doctype包括html标签都是一样的,所以子类不再需要关心这些。当然上述LZ写的有点粗糙,其实我们可以定义的更仔细一点,比如head标签里,第一个是title,然后是meta等等。但作为例子,我们还是遵循简单的原则,主要还是想给各位传达模板方法模式的思想。

模板方法模式是所有设计模式当中,LZ觉得最无侵入性的模式,因为它的好处实在是太明显了。模板方法模式并不强制接口的实现类必须继承,所以不会对子类造成任何影响,而如果子类的实现可以配得上模板类的模板,那么就可以享受模板方法模式带来的好处。

通常情况下,模板方法模式用于定义构建某个对象的步骤与顺序,或者定义一个算法的骨架。

我们刚才的示例明显就是构建一个String对象的过程,在这里要声明一点,对于模板方法模式,父类提供的构建步骤和顺序或者算法骨架,通常是不希望甚至是不允许子类去覆盖的,所以在某些场景中,可以直接将父类中提供骨架的方法声明为final类型。

模板方法模式还有一种使用的方式,为了给子类足够的自由度,可以提供一些方法供子类覆盖,去实现一些骨架中不是必须但却可以有自定义实现的步骤。

比如上述的例子当中,我们应该都知道,HTML页面中有一些标签是可有可无的。比如meta标签,link标签,script标签等。那么我们可以将刚才的例子细化一下,去看一下上面说的供子类覆盖的方法是什么。我们将刚才的抽象父类细化成如下形式。

[java]
public abstract class AbstractPageBuilder implements PageBuilder{

private static final String DEFAULT_DOCTYPE = "";

private static final String DEFAULT_XMLNS = "http://www.w3.org/1999/xhtml";

private StringBuffer stringBuffer = new StringBuffer();

public String bulidHtml() {
stringBuffer.append(DEFAULT_DOCTYPE);
stringBuffer.append("");
stringBuffer.append("");
appendTitle(stringBuffer);
appendMeta(stringBuffer);
appendLink(stringBuffer);
appendScript(stringBuffer);
stringBuffer.append("");
appendBody(stringBuffer);
stringBuffer.append("");
return stringBuffer.toString();
}

protected void appendMeta(StringBuffer stringBuffer){
}

protected void appendLink(StringBuffer stringBuffer){
}

protected void appendScript(StringBuffer stringBuffer){
}

protected abstract void appendTitle(StringBuffer stringBuffer);

protected abstract void appendBody(StringBuffer stringBuffer);

}

public abstract class AbstractPageBuilder implements PageBuilder{

private static final String DEFAULT_DOCTYPE = "";

private static final String DEFAULT_XMLNS = "http://www.w3.org/1999/xhtml";

private StringBuffer stringBuffer = new StringBuffer();

public String bulidHtml() {
stringBuffer.append(DEFAULT_DOCTYPE);
stringBuffer.append("");
stringBuffer.append("");
appendTitle(stringBuffer);
appendMeta(stringBuffer);
appendLink(stringBuffer);
appendScript(stringBuffer);
stringBuffer.append("");
appendBody(stringBuffer);
stringBuffer.append("");
return stringBuffer.toString();
}

protected void appendMeta(StringBuffer stringBuffer){
}

protected void appendLink(StringBuffer stringBuffer){
}

protected void appendScript(StringBuffer stringBuffer){
}

protected abstract void appendTitle(StringBuffer stringBuffer);

protected abstract void appendBody(StringBuffer stringBuffer);

}
可以看到,我们将head标签的生成过程更加细化了,分成四个方法,title,meta,link和script。但是这四个里面appendTitle是模板方法,子类必须实现,而其它三个则是普通的空方法。

那么上述三个方法,就是留给子类覆盖的,当然子类可以选择不覆盖,那么生成的HTML就没有meta,link和script这三种标签,如果想有的话,就可以覆盖其中任意一个,比如下面这样。

[java]
public class MyPageBuilder extends AbstractPageBuilder{

protected void app