设计模式之模板方法体会

来源:互联网 发布:天庭淘宝店 下载 编辑:程序博客网 时间:2024/06/07 08:08

摘要

设计模式中的模板方法是一种很常见的设计模式,今天重新看mblog的代码的Velocity自定义指令部分代码实现时,看到了一处比较不错的模板方法的实现,在这里记录一下。

模板方法

个人的理解是接口或者父类对子类公共方法的高度抽象,口或者父类并不对这些方法具体,而是子类根据自已特定的场景进行实现。接口或父类指是留了一下统一的模板。
下面是我龟兔赛跑为例给出一个简单的模板方法的例子。
首先,抽象出动物这个类,代码如下:
//将比赛中公共部分抽象到Animal类中public class Animal implements Runnable{//动物跑步的速度private final Integer velocity;private final String name;public Animal(Integer velocity,String name){     super();     this.velocity=velocity;     this.name=name;}@Overridepublic void run() {     Long startTime=System.currentTimeMillis();     startRace();     Long endTime=System.currentTimeMillis();     System.out.println(String.format("%s:跑完的时间为%s豪秒", getName(),endTime-startTime));}public void startRace(){     //TODO 子类中实现具体的比赛规则}public Integer getVelocity() {     return velocity;}public String getName() {     return name;}}

这个实现Runable接口,来在进程中模拟跑步,我们将一些公共的部分抽象到了Aniaml类中,而startRace方法由具体实现类完成。
public class Race {//比赛的长度    public final static Integer raceLength=1000000;public static void main(String args[]){Thread rabbit=new Thread( new Animal(1000,"rabbit") {@Overridepublic void startRace(){for(int i=0;i<raceLength;){i+=getVelocity();try {//兔子在比赛中睡觉的时间int sleepTime= new Random().nextInt(10);Thread.sleep(sleepTime);} catch (InterruptedException e) {e.printStackTrace();}}}});Thread tortoise=new Thread( new Animal(1,"tortoise") {@Overridepublic void startRace(){for(int i=0;i<raceLength;){i+=getVelocity();}}});rabbit.start();tortoise.start();}}
比赛Race类中我们分别用匿名类实现了兔子与乌龟自己特定的startRace方法,兔子跑的更快(velocity的值更大),但中间经常睡觉(Thread.sleep),而乌龟则跑的更慢(velocity的值更小)。

mblog中自定义的Directive

首先来看一下Velocity的实现自定义指令要继承的类
public abstract class Directive implements DirectiveConstants, Cloneable{      //省略部分代码    /**     * Return the name of this directive.在velocity模析中使用的指令名字     * @return The name of this directive.     */    public abstract String getName();    /**     * Get the directive type BLOCK/LINE. 指令的类型     * @return The directive type BLOCK/LINE.     */    public abstract int getType();    /**     * How this directive is to be rendered,指定如何被渲染     * @param context     * @param writer     * @param node     * @return True if the directive rendered successfully.     * @throws IOException     * @throws ResourceNotFoundException     * @throws ParseErrorException     * @throws MethodInvocationException     */    public abstract boolean render( InternalContextAdapter context,                                    Writer writer, Node node )           throws IOException, ResourceNotFoundException, ParseErrorException,                MethodInvocationException;}
可以看看Directive抽象类中一共有三的方法让子类去实现。
来来看看mblog中比较牛的一处实现
public abstract class BaseDirective extends Directive {public abstract void initBean();public abstract boolean render(RenderHandler handler) throws RuntimeException, IOException;/**  * 重载init方法,初始自定义指令的配制参数  */  @Override  public void init(RuntimeServices rs, InternalContextAdapter context, Node node)      throws TemplateInitException {      super.init(rs, context, node);        initBean();}//牛牛的实现,new RenderHandler(context, writer, node)@Override    public boolean render(InternalContextAdapter context, Writer writer, Node node) throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException {return render(new RenderHandler(context, writer, node));}public Paging wrapPaing(int pn) {return new Paging(pn, 12);}}
BaseDirective类实现了类的render方法调用自己的render方法,而其同样采用了模板方法,initBean 和render交给子类去实现。为什么说的BaseDirective的实现很牛呢?就在于这个return render(new RenderHandler(context,witer,node));
先看看RenderHandler类的代码:
public class RenderHandler extends BaseHandler {private InternalContextAdapter context;private Writer writer;private Node node;private Map<String, Object> parameters = new HashMap<String, Object>();public RenderHandler(InternalContextAdapter context, Writer writer, Node node) {this.context = context;this.writer = writer;this.node = node;}public void put(String key, Object value) {parameters.put(key, value);}/** * 在context中放入变量,具体处理留给自定义指令下面的脚本 */public void doRender() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException {Map<String, Object> reduceMap = reduce();getBody().render(context, writer);reduce(reduceMap);}/**  * 1、将parameters中的key-value放入context * 2、返回原context中key与parameters中key相同时对应的key-value * @return  */private Map<String, Object> reduce() {Map<String, Object> reduceMap = new HashMap<>();parameters.forEach((k, v) -> {if (context.containsKey(k)) {reduceMap.put(k, context.get(k));}context.put(k, v);});return reduceMap;}/** * 1、删除context中来源于parameters的key-value * 2、将原来context中key与parameters中key相同时对应的reduceMap放回context * @param reduceMap */private void reduce(Map<String, Object> reduceMap) {for (String key : parameters.keySet()) {context.remove(key);}reduceMap.forEach((k, v) -> {context.put(k, v);});}public void write(String str) throws IOException {writer.write(str);}public HttpServletRequest getRequest() {ViewToolContext viewContext = (ViewToolContext)context.getInternalUserContext();        return viewContext.getRequest();        }public Writer getWriter() {return writer;}public InternalContextAdapter getContext() {return context;}public Node getParameter(int index) {        if (node.jjtGetNumChildren() > index && node.jjtGetChild(index) != null) {            return node.jjtGetChild(index);        }        return null;    }    public int getIntParameter(int index) {        if (node.jjtGetNumChildren() > index && node.jjtGetChild(index) != null) {            Node n = node.jjtGetChild(index);            return toInt(n.value(context));        }        return 0;    }    public long getLongParameter(int index) {        if (node.jjtGetNumChildren() > index && node.jjtGetChild(index) != null) {            Node n = node.jjtGetChild(index);            return toLong(n.value(context));        }        return 0;    }    public String getStringParameter(int index) {        if (node.jjtGetNumChildren() > index && node.jjtGetChild(index) != null) {            Node n = node.jjtGetChild(index);            return (String) n.value(context);        }        return null;    }        /**     * 当自定义的Driective的type为BLOCK时,返回包含在该自定义指令下的脚本内容     * @return     */    public Node getBody() {        if (node.jjtGetNumChildren() > 0) {            Node n= node.jjtGetChild(node.jjtGetNumChildren() - 1);            return n;        }        return null;    }}
可以看看它里面抽象出了很多与Directiver操作的方法比如getBody、getParameter、getIntParameter同时抽象出得到请求的方法getRequest,这里方法都是自定义指令时经常会用的方法。
通过render(new RenderHandler(context,witer,node))一行代码,继承BaseDirective类的子类便可以在实现render方法时,拿到了一些公共方法而不去每在自已的实现中再写一篇这些方法。有人可能会说直接把这些方法写在BaseDirective中而不是RenderHandler中也可以呀。但这样做不好,这些方法全偶合在了BaseDirective中了。抽象到RenderHandler中方便后面的扩展。


1 0