首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 第二书店 程序员
您的位置:Java->Groovy探索之Builder 三

Groovy探索之Builder 三2008-05-08 来自:villa123  [收藏到我的网摘]

因为我们知道builder模式是从使用MarkupBuilder开始的,而MarkupBuilder是生成xml文件的。很自然的,当我想做第一个自己的builder的时候,我就会做一个table的builder。用来生成如下的代码:

Name
Age
Address


tom
33
Shenzhen


mike
22
Taibei



在看下面的文字之前,诸位大虾可以考虑一下自己试着实现上面的功能。
虽然我们在上一篇文字中已经详细的介绍了BuilderSupport的各个方法的功能,但要实现上面的功能,却实实在在的有些难度。下面让我们一点一点的来解析它的实现。
要分析一个问题,我们总是首先从最简单的开始。所以我们首先看标签的实现。对于“Name”这样的代码,我们可以想象,在创建的时候,肯定是如下的代码:
builder.td 'Name'

这样的代码我们熟悉,也就是方法名加上一个参数,调用的是BuilderSupport的“createNode(Object name, Object value)”方法。
而如果是下面的代码:
Name

这样的代码,在创建的时候,肯定是这样写:
builder.td([rowspan:'4'],'Name')

也就是说它会调用BuilderSupport的“createNode(Object name, Map attributes, Object value)”方法。

同理分析,可以得知“”会调用BuilderSupport的“createNode(Object name)”方法。

使用同样的方法对“”标签进行分析,也会得到同样的结果。但“tr”标签的难点在于标签里要嵌入“td”标签。
比如,对于代码“builder.td 'Name'”,我们可以如下实现:
protected Object createNode(Object name, Object value){
sb<<"<"
sb< sb<<">"
sb< sb<<" sb< sb<<">"

}

一次就可以把整个标签实现了。但对于“builder.tr”,我们却不能实现成下面的样子:
protected Object createNode(Object name){
sb<<"<"
sb< sb<<">"

sb<<" sb< sb<<">"

}


很明显,因为“tr”标签里要嵌入“td”标签的,如果写成上面的样子,那么生成的代码如下:


中间就没有办法嵌入“td”标签了。
分析到了这里,才找到了我们实现整个业务需求的难点所在。如何解决这个问题呢?答案就是BuilderSupport的“nodeCompleted(Object parent, Object node)”方法。
下面我们来看看整个类是如何实现的:
class HtmlTrBuilder extends BuilderSupport {

private StringBuffer sb = new StringBuffer();

这个StringBuffer对象用来存储“tr”和“td”实现的内容。
def isTd = true;
一个标记,证明正在调用的方法操作的是“td”标签,它是实现我们这个业务难点的关键标记。用处在下面会进一步说明。
protectedvoid setParent(Object parent, Object child){

}

“setParent”方法对我们没有用处,我们不对它做任何操作。
protected Object createNode(Object name){

sb<<"<"<"
if(name.toString().toLowerCase() == 'td')
{
sb<<""
isTd = true
}
}

当方法名为“td”的时候,生成“”来结束该标签,同时,置isTd为“true”。当然,如果方法名为“tr”的时候就不能结束了。
那么为什么要置isTd为“true”呢?我们先来看看“nodeCompleted(Object parent, Object node)”方法的实现:
protectedvoid nodeCompleted(Object parent, Object node) {
if(!this.isTd)
{
this.sb<<''
}
else
{
this.isTd = false;
}
}

看到这个方法,我们就明白了为什么要置isTd为“true”,因为如果isTd为“false”的话,在“nodeCompleted”方法里就要执行“this.sb<<''”,也就是关闭了“tr”标签。
同样的道理,下面的这三个方法就不难理解了:
protected Object createNode(Object name, Object value){
sb<<"<"
sb< sb<<">"
sb< if(name.toString().toLowerCase() == 'td')
{
sb<<""
isTd = true
}
}

protected Object createNode(Object name, Map attributes){

sb<<"<"
sb< sb<<" "
attr.each{
it ->
sb< sb<<"=\""
sb< sb<<"\""
}
sb<<">"
if(name.toString().toLowerCase() == 'td')
{
sb<<""
isTd = true
}

}

protected Object createNode(Object name, Map attributes, Object value){

sb<<"<"
sb< sb<<" "
attr.each{
it ->
sb< sb<<"=\""
sb< sb<<"\""
}
sb<<">"
sb.append(value.toString())
if(name.toString().toLowerCase() == 'td')
{
sb<<""
isTd = true
}

}
}

这样就实现了整个业务的要求。然后再对整个代码进行一下整理,把该提出来的代码提出来。得到如下的实现:
class HtmlTrBuilder extends BuilderSupport {

private StringBuffer sb = new StringBuffer();

def isTd = true;

def makeWithAttr = {
name,attr ->
sb<<"<"
sb< sb<<" "
attr.each{
it ->
sb< sb<<"=\""
sb< sb<<"\""
}
sb<<">"
}

def doTdEnd = {
name ->
if(name.toString().toLowerCase() == 'td')
{
sb<<""
isTd = true
}

}

protectedvoid setParent(Object parent, Object child){

}

protected Object createNode(Object name){

sb<<"<"<"
doTdEnd.call(name)
}

protected Object createNode(Object name, Object value){
sb<<"<"
sb< sb<<">"
sb< doTdEnd.call(name)
}

protected Object createNode(Object name, Map attributes){

makeWithAttr.call(name,attributes)
doTdEnd.call(name)

}

protected Object createNode(Object name, Map attributes, Object value){

makeWithAttr.call(name,attributes)
sb.append(value.toString())
doTdEnd.call(name)

}

protectedvoid nodeCompleted(Object parent, Object node) {
if(!this.isTd)
{
this.sb<<''
}
else
{
this.isTd = false;
}
}
}

最后,我们来对上面的代码进行测试:
HtmlTrBuilder htb = new HtmlTrBuilder()

htb.tr
{
td([rowspan:'2'],'a')
td([colspan:'3'],'b')
td 'c'
td 'd'
td 'e'
td([rowspan:'3'],'f')
}

htb.tr
{
td([colspan:'2'],'g')
td 'h'
td 'i'
td 'j'
td 'k'
}

htb.tr
{
td 'l'
td 'm'
td 'n'
td 'o'
td 'p'
td 'q'
td 'r'
}

println htb.sb.toString()

运行结果为:
abcdefghijklmnopqr

推荐人评论

因为我们知道builder模式是从使用MarkupBuilder开始的,而MarkupBuilder是生成xml文件的。很自然的,当我想做第一个自己的builder的时候,我就会做一个table的builder。

用户评论

正在载入评论列表...

是谁推荐了此篇文章

专家头像陈丽辉CSDN频道编辑,联系方式chenlh@csdn.net
个人blog发送信息
陈丽辉推荐的其他文章

赞助商精华文章

热点新闻

热点评论

    精彩视频

    精彩专题

    资源下载

      网站简介广告服务网站地图帮助联系方式诚聘英才English问题报告
    北京世纪乐知数码科技有限公司  版权所有  京 ICP 证 020026 号
    Copyright © 2000-2006, CSDN.NET, All Rights Reserved