Groovy探索之Builder 三
发布时间:2020-12-14 16:59:55 所属栏目:大数据 来源:网络整理
导读:???????????????????????????? Groovy探索之Builder 三 ? ? 因为我们知道builder模式是从使用 MarkupBuilder 开始的,而 MarkupBuilder 是生成xml文件的。很自然的,当我想做第一个自己的builder的时候,我就会做一个table的builder。用来生成如下的代码: t
????????????????????????????
Groovy探索之Builder 三
?
?
因为我们知道builder模式是从使用
MarkupBuilder开始的,而
MarkupBuilder是生成xml文件的。很自然的,当我想做第一个自己的builder的时候,我就会做一个table的builder。用来生成如下的代码:
<tr>
??????? <td>Name</td>
??????? <td>Age</td>
??????? <td>Address</td>
</tr>
<tr>
??????? <td>tom</td>
??????? <td>33</td>
??????? <td>Shenzhen</td>
</tr>
<tr>
??????? <td>mike</td>
??????? <td>22</td>
??????? <td>Taibei</td>
</tr>
?
?
在看下面的文字之前,诸位大虾可以考虑一下自己试着实现上面的功能。
虽然我们在上一篇文字中已经详细的介绍了
BuilderSupport的各个方法的功能,但要实现上面的功能,却实实在在的有些难度。下面让我们一点一点的来解析它的实现。
要分析一个问题,我们总是首先从最简单的开始。所以我们首先看<td>标签的实现。对于“<td>Name</td>”这样的代码,我们可以想象,在创建的时候,肯定是如下的代码:
builder.
td
'Name'
?
这样的代码我们熟悉,也就是方法名加上一个参数,调用的是
BuilderSupport的“
createNode(Object name,Object value)”方法。
而如果是下面的代码:
<td colspan=”4”>Name</td>
?
这样的代码,在创建的时候,肯定是这样写:
builder.
td([rowspan:
'4'
],
'Name'
)
?
也就是说它会调用
BuilderSupport
的“
createNode(Object name,Map attributes,Object value)
”方法。
?
同理分析,可以得知“
<td></td>
”会调用
BuilderSupport
的“
createNode(Object name)
”方法。
?
使用同样的方法对“
<tr>
”标签进行分析,也会得到同样的结果。但“
tr
”标签的难点在于标签里要嵌入“
td
”标签。
比如,对于代码“builder.
td
'Name'
”,我们可以如下实现:
???
protected
Object createNode(Object name,Object value){
?????? sb<<
"<"
?????? sb<<name.toString()
?????? sb<<
">"
?????? sb<<value.toString()
?????? sb<<
"</"
?????? sb<<name.toString()
?????? sb<<
">"
?
}
?
一次就可以把整个标签实现了。但对于“builder.
tr
”,我们却不能实现成下面的样子:
protected
Object createNode(Object name){
?????? sb<<
"<"
?????? sb<<name.toString()
?????? sb<<
">"
??????
?????? sb<<
"</"
?????? sb<<name.toString()
?????? sb<<
">"
?
}
?
?
很明显,因为“tr”标签里要嵌入“td”标签的,如果写成上面的样子,那么生成的代码如下:
<tr></tr>
?
中间就没有办法嵌入“
td
”标签了。
分析到了这里,才找到了我们实现整个业务需求的难点所在。如何解决这个问题呢?答案就是
BuilderSupport
的“
nodeCompleted(Object parent,Object node)
”方法。
下面我们来看看整个类是如何实现的:
class
HtmlTrBuilder
extends
BuilderSupport {
???
private
StringBuffer sb =
new
StringBuffer();
?
这个
StringBuffer
对象用来存储“
tr
”和“
td
”实现的内容。
???
def
isTd =
true
;
一个标记,证明正在调用的方法操作的是“
td
”标签,它是实现我们这个业务难点的关键标记。用处在下面会进一步说明。
???
protected
void
setParent(Object parent,Object child){
???????
??? }
?
“
setParent
”方法对我们没有用处,我们不对它做任何操作。
???
protected
Object createNode(Object name){
??????
?????? sb<<
"<"
<<name.toString()<<
">"
??????
if
(name.toString().toLowerCase() ==
'td'
)
?????? {
?????????? sb<<
"</"
<<name.toString()<<
">"
?????????? isTd =
true
?????? }
}
?
当方法名为“
td
”的时候,生成“
</td>
”来结束该标签,同时,置
isTd
为“
true
”。当然,如果方法名为“
tr
”的时候就不能结束了。
那么为什么要置
isTd
为“
true
”呢?我们先来看看“
nodeCompleted(Object parent,Object node)
”方法的实现:
???
protected
void
nodeCompleted(Object parent,Object node) {
??????
if
(!
this
.isTd)
?????? {
??????????
this
.sb<<
'</tr>'
?????? }
??????
else
?????? {
??????????
this
.isTd =
false
;
?????? }
}
?
看到这个方法,我们就明白了为什么要置
isTd
为“
true
”,因为如果
isTd
为“
false
”的话,在“
nodeCompleted
”方法里就要执行“
this
.sb<<
'</tr>'
”,也就是关闭了“
tr
”标签。
同样的道理,下面的这三个方法就不难理解了:
???
protected
Object createNode(Object name,Object value){
?????? sb<<
"<"
?????? sb<<name.toString()
?????? sb<<
">"
?????? sb<<value.toString()
??????
if
(name.toString().toLowerCase() ==
'td'
)
?????? {
?????????? sb<<
"</"
<<name.toString()<<
">"
?????????? isTd =
true
?????? }
??? }
?
???
protected
Object createNode(Object name,Map attributes){
??????
?????? ??? sb<<
"<"
?????????? sb<<name.toString()
?????????? sb<<
" "
?????????? attr.
each
{
????????????? it ->
????????????????? sb<<it.key.toString()
????????????????? sb<<
"=/""
????????????????? sb<<it.value.toString()
????????????????? sb<<
"/""
?????????? }
?????????? sb<<
">"
??????
if
(name.toString().toLowerCase() ==
'td'
)
?????? {
?????????? sb<<
"</"
<<name.toString()<<
">"
?????????? isTd =
true
?????? }
??????
??? }
???
???
protected
Object createNode(Object name,Object value){
??????
?????? ??? sb<<
"<"
?????????? sb<<name.toString()
?????????? sb<<
" "
?????????? attr.
each
{
????????????? it ->
????????????????? sb<<it.key.toString()
????????????????? sb<<
"=/""
????????????????? sb<<it.value.toString()
????????????????? sb<<
"/""
?????????? }
?????????? sb<<
">"
?????? sb.
append
(value.toString())
??????
if
(name.toString().toLowerCase() ==
'td'
)
?????? {
?????????? sb<<
"</"
<<name.toString()<<
">"
?????????? isTd =
true
?????? }
??????
}
}
?
这样就实现了整个业务的要求。然后再对整个代码进行一下整理,把该提出来的代码提出来。得到如下的实现:
class
HtmlTrBuilder
extends
BuilderSupport {
???
???
private
StringBuffer sb =
new
StringBuffer();
???
???
def
isTd =
true
;
???
???
def
makeWithAttr = {
?????????? name,attr ->
?????????? sb<<
"<"
?????????? sb<<name.toString()
?????????? sb<<
" "
?????????? attr.
each
{
????????????? it ->
????????????????? sb<<it.key.toString()
????????????????? sb<<
"=/""
????????????????? sb<<it.value.toString()
????????????????? sb<<
"/""
?????????? }
?????????? sb<<
">"
??? }
???
???
def
doTdEnd = {
?????????? name ->
??????????
if
(name.toString().toLowerCase() ==
'td'
)
?????????? {
????????????? sb<<
"</"
<<name.toString()<<
">"
????????????? isTd =
true
?????????? }
??????????
??? }
???
???
protected
void
setParent(Object parent,Object child){
???????
??? }
???
???
protected
Object createNode(Object name){
??????
?????? sb<<
"<"
<<name.toString()<<
">"
?????? doTdEnd.
call
(name)
??? }
???
???
protected
Object createNode(Object name,Object value){
?????? sb<<
"<"
?????? sb<<name.toString()
?????? sb<<
">"
?????? sb<<value.toString()
?????? doTdEnd.
call
(name)
??? }
?
???
protected
Object createNode(Object name,Map attributes){
??????
?????? makeWithAttr.
call
(name,attributes)
?????? doTdEnd.
call
(name)
??????
??? }
???
???
protected
Object createNode(Object name,Object value){
??????
?????? makeWithAttr.
call
(name,attributes)
?????? sb.
append
(value.toString())
?????? doTdEnd.
call
(name)
??????
??? }
???
???
protected
void
nodeCompleted(Object parent,Object node) {
??????
if
(!
this
.isTd)
?????? {
??????????
this
.sb<<
'</tr>'
?????? }
??????
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()
?
运行结果为:
<tr><td rowspan="2">a</td><td colspan="3">b</td><td>c</td><td>d</td><td>e</td><td rowspan="3">f</td></tr><tr><td colspan="2">g</td><td>h</td><td>i</td><td>j</td><td>k</td></tr><tr><td>l</td><td>m</td><td>n</td><td>o</td><td>p</td><td>q</td><td>r</td></tr>
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |