﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-ajoo-文章分类-名著类</title><link>http://www.blogjava.net/ajoo/category/6968.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 11:17:04 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 11:17:04 GMT</pubDate><ttl>60</ttl><item><title>论面向组合子程序设计方法 之九 南无阿弥陀佛</title><link>http://www.blogjava.net/ajoo/articles/27850.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Fri, 13 Jan 2006 01:11:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27850.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27850.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27850.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27850.html</trackback:ping><description><![CDATA[<table class="forumline" align="center" border="0" cellpadding="3" cellspacing="1" width="100%">
<tbody><tr><td class="row1" valign="top" width="100%">
	<span class="postdetails">其实，前面我还忘了提一个非常重要的基本组合子：singleton。
<br>
这里补充提一下：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> SingletonComponent <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> c;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(170, 170, 221);">Object</span> val;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> c.<span style="color: rgb(0, 0, 0);">getType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> synchronized <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>val!=<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span><span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> val;
<br>
&nbsp; &nbsp; val = c.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> val;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> synchronized <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>val!=<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span><span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> val.<span style="color: rgb(0, 0, 0);">getClass</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> c.<span style="color: rgb(0, 0, 0);">verify</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
代码没什么可说的，就是最简单的singleton模式。
<br>

<br>
用这个组合子，我们可以对任意的Component做singleton。
<br>

<br>
下面接着说monad。
<br>

<br>
有了bind，很多的功能都可以自然推演出来了。
<br>

<br>
比如我们前面用来刁难pico的那个例子，甚至，为了更强调复杂性，我们可以给B和A再另外增加一些参数，这些参数要求从容器解析（毕竟，我们之所以需要容器，就是为了自动解析一些依赖关系，要是全部依赖关系都hard-code，意义就不大了）：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> A createA<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; B b = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> B<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> A<span style="color: rgb(0, 0, 0);">(</span>b,b, ...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
用bind，我们的思路可以是这样：
<br>
1。用B的构造函数生成一个Component。
<br>
2。这个Component生成一个对象，
<br>
3。这个产生的对象被传递给一个对应A的Component当作参数。这一步可以用bind来搞定。
<br>

<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
<span style="color: rgb(170, 170, 221);">Component</span> b_component = Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>B.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> BoundComponent<span style="color: rgb(0, 0, 0);">(</span>b_component, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> b<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> arg = Components.<span style="color: rgb(0, 0, 0);">value</span><span style="color: rgb(0, 0, 0);">(</span>b<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> WithArgument<span style="color: rgb(0, 0, 0);">(</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> WithArgument<span style="color: rgb(0, 0, 0);">(</span>a, <span style="color: rgb(0, 0, 0);">0</span>, arg<span style="color: rgb(0, 0, 0);">)</span>,
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">1</span>, arg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
Components.value(Object)是我们写的一个对ValueComponent的封装静态函数。
<br>
为了避免总写冗长的new SomeComponent(...)，我们把一些常用的基本Component都写成名字较短的静态函数，放在Components类里面。
<br>

<br>
这样，我们可以写Components.value(obj)，而不是new ValueComponent(obj)。
<br>
要是觉得敲键盘还是麻烦，你甚至可以创建一个Components对象cc。然后到处用这个对象：
<br>
cc.value(obj)。舒服些了吧？
<br>

<br>

<br>
从上面的例子，我们可以看到，那个直接创建对象的createA函数中的两个步骤，在我们高阶的Component中也被分为两部。
<br>
而在两个步骤之间的信息传递（那个b变量，从第一个步骤取得，然后在第二个步骤使用），则被用bind操作实现了。
<br>

<br>
到这，也许我们该伸伸懒腰了。舒服地往椅子背上一靠，说：“啊。终于干完了！我可以用高阶逻辑来模拟任何直接硬编码创建对象的逻辑了”。
<br>

<br>
这话倒也没错，有了bind，我们不再被局限于“构造函数注射”，“setter注射”，“静态工厂注射”等寥寥几个注射方式；我们甚至可以对所谓的ioc type嗤之以鼻：“什么type1, type2？不过是我们可以处理的无数种情况中的几种特例而已！”。
<br>我们可以处理if-else，可以处理循环，递归，任何可以直接用java写出来的对象创建方式，我们都可以在高阶逻辑上得到对应的组合版本，只
要我们有足够的原子组合子。（所谓原字组合子，不过是：FunctionComponent,
BeanComponent，ValueComponent几种）
<br>

<br>
比如，对应于：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
X createX<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; A a = A.<span style="color: rgb(0, 0, 0);">instance</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>a.<span style="color: rgb(0, 0, 0);">isX</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> X<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Y<span style="color: rgb(0, 0, 0);">(</span>a, ...<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">getX</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
这里，所有的省略号都代表可能需要从容器解析的参数。使用高阶Component对象而不是直接调用createX()函数的一个原因，就是我们想要把依赖解析隐藏起来并且集中灵活地配置和管理。
<br>

<br>

<br>
对此，我们可以写成：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Component</span> a_component = Components.<span style="color: rgb(0, 0, 0);">static_method</span><span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span>, "instance"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> BoundComponent<span style="color: rgb(0, 0, 0);">(</span>a_component, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span> a<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> isx_component = Components.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>a, "isX"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> BoundComponent<span style="color: rgb(0, 0, 0);">(</span>isx_component, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> isx<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Boolean</span> v = <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Boolean</span><span style="color: rgb(0, 0, 0);">)</span>isx;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>v.<span style="color: rgb(0, 0, 0);">booleanValue</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>X.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Coponent y_component =
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> WithArgument<span style="color: rgb(0, 0, 0);">(</span>Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>Y.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>, <span style="color: rgb(0, 0, 0);">0</span>,
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Components.<span style="color: rgb(0, 0, 0);">value</span><span style="color: rgb(0, 0, 0);">(</span>a<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> BoundComponent<span style="color: rgb(0, 0, 0);">(</span>y_component, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> y<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>y, "getX"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
稍微有点绕，如果你到此有点糊涂的话，请重温一下前面的简单的bind的例子，只要体会了bind的具体意义，上面的代码不过是几层bind的嵌套。
<br>

<br>

<br>
好，如果你理解了bind，那么应该能够看懂上面的这段代码了。它其实就是那个createX函数的严格翻译。
<br>

<br>
功能确实很强大了，就是这代码写起来这个<span style="font-weight: bold;">烦</span>啊！对比一下createX和这个高阶版本吧。我发现如果我多看几眼这个所谓的"co"的代码，我简直都要吐！如果说createX这个函数的代码是正常人说话，那么这个高阶代码就是唐僧念经：“南无阿弥陀佛，南无阿弥陀佛，南无阿弥陀佛...”，天啊！
<br>

<br>

<br>
如果我们真要Combinator-oriented起来，难道要整天写这种蹩脚代码？是不是我们吐啊吐的就会习惯了呢？
<br>
pico的各个ComponentAdapter其实倒也就是这么写，可是pico没有bind，你很少需要写这么深的嵌套，甚至很少需要写匿名类。
<br>
如果我们把我们的组件系统比喻作pascal语言的话，pico的那些decorator充其量不过是一个dos的批处理，不，远不如批处理灵活，应该也就是一个简单的用户界面上的几个按钮。
<br>

<br>
那么有没有什么办法来简化语法呢？
<br>

<br>
倒是有一个想法：
<br>
1。把Component从接口变成一个抽象类。然后把一些常用的二元组合，比如bind，比如withArgument，withProperty，比如method，ifelse，都放在这个抽象类里面。这样，
<br>

<br>
我们就可以避免写：
<br>
new SingletonComponent(c)，而写c.singleton()。
<br>
我们就可以避免写：
<br>
new BoundComponent(c1, ...)，而写：c1.bind(...)。
<br>
可以避免写：
<br>
new WithArgument(c, 0, arg)，而写：c.withArgument(0, arg)。
<br>
可以避免写：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> BoundComponent<span style="color: rgb(0, 0, 0);">(</span>c1, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> obj<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>obj, "method"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
而写成：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
c1.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>"method"<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
可以避免写：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> BoundComponent<span style="color: rgb(0, 0, 0);">(</span>c1, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> obj<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Boolean</span><span style="color: rgb(0, 0, 0);">)</span>obj<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">booleanValue</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> a;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> b;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
而写成：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
c1.<span style="color: rgb(0, 0, 0);">ifelse</span><span style="color: rgb(0, 0, 0);">(</span>a,b<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
等等等等。
<br>

<br>
这样做，从架构上确实有点损害，我们牺牲了“围绕接口”的原则，而改为围绕抽象类了。
<br>

<br>
但是，从实际效果考虑，我发现它损失的架构上的美感，远远比不上它带来的编码上的方便程度。谁让我们用的是java呢，世上没有十全十美的事情，就凑合吧。
<br>

<br>
经过这个改动，上面的对应createX的高阶代码变成：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Component</span> a_component = Components.<span style="color: rgb(0, 0, 0);">static_method</span><span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span>, "instance"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> a_component.<span style="color: rgb(0, 0, 0);">bind</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Binder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span> a<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> isx_component = Components.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>a, "isX"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> isx_component.<span style="color: rgb(0, 0, 0);">ifelse</span><span style="color: rgb(0, 0, 0);">(</span>
<br>
&nbsp; &nbsp; &nbsp; Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>X.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>,
<br>
&nbsp; &nbsp; &nbsp; Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>Y.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">0</span>, Components.<span style="color: rgb(0, 0, 0);">value</span><span style="color: rgb(0, 0, 0);">(</span>a<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>"getX"<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
稍微好些了。而如果我们不需要给Y的构造函数指定参数，那么效果还会更好。
<br>
比如对
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
X createX<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; A a = A.<span style="color: rgb(0, 0, 0);">instance</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>a.<span style="color: rgb(0, 0, 0);">isX</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> X<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Y<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">getX</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
高阶代码会变成：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Component</span> a_component = Components.<span style="color: rgb(0, 0, 0);">static_method</span><span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span>, "instance"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> a_component.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>"isX"<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">ifelse</span><span style="color: rgb(0, 0, 0);">(</span>
<br>
&nbsp; &nbsp; Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>X.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>,
<br>
&nbsp; &nbsp; Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>Y.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">0</span>, Components.<span style="color: rgb(0, 0, 0);">value</span><span style="color: rgb(0, 0, 0);">(</span>a<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>"getX"<span style="color: rgb(0, 0, 0);">)</span>
<br>
<span style="color: rgb(0, 0, 0);">)</span>;
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
又简洁了不少。
<br>

<br>

<br>
当然，说实话，如果我们把情况任意复杂化，比如：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
Y createY<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; a = A.<span style="color: rgb(0, 0, 0);">createA</span><span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; b = B.<span style="color: rgb(0, 0, 0);">createB</span><span style="color: rgb(0, 0, 0);">(</span>a, ...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; c = C.<span style="color: rgb(0, 0, 0);">createC</span><span style="color: rgb(0, 0, 0);">(</span>a,b,...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Y.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>a,b,c,...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
要对createY写出高阶对应版本，这bind要嵌套三层，代码无论如何不可能好看了。对此，我们只能耸耸肩说：无能为力了。因为我们这里已经接触到了java语言的底线。
<br>

<br>
值得欣慰的是，至少：
<br>
1。对简单需求，比如pico能够处理的那些，我们的语法并不比pico麻烦。
<br>2。对复杂需求，pico不能处理，而只能通过自己实现ComponentAdapter实现；而我们的co构建出来的系统，在没有剥夺你自己实
现Component的前提下，也提供了采用声明式的语法来组合的方式。至于是选择用熟悉的java语法来过程式地自己处理依赖，还是用声明式的高阶逻辑
来仍然让系统处理依赖，则是程序员的自由了。
<br>

<br>
我们推荐，除非对非常复杂的需求，还是用声明式的组合来处理更好。
<br>

<br>

<br>
写到这里，不得不唠叨一些语言了。就象是你也可以在c这个过程语言里面使用一些oo的技巧一样，我们在java这个oo语言里面是可以使用一些co的技巧的。
<br>

<br>
只不过，缺乏语言上的良好支持，让我们在采用co设计的时候的代价有所增大。如何权衡？是co带来的缺点（不方便调试，运行效率低，语法麻烦）大，还是它带来的好处（灵活应对变化，减少代码数量，方便重用）大，则是一个需要主观经验决定的事情了。
<br>

<br>

<br>

<br>
其实，在一个真正支持monad组合子的语言里面，createY会被类似写成这样：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">do</span>
<br>
&nbsp; a &lt;- static_method<span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span>, "createA"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; b &lt;- static_method<span style="color: rgb(0, 0, 0);">(</span>B.<span style="color: rgb(0, 0, 0);">class</span>, "createB"<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">0</span>, a<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; c &lt;- static_method<span style="color: rgb(0, 0, 0);">(</span>C.<span style="color: rgb(0, 0, 0);">class</span>, "createC"<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">0</span>, a<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">1</span>, b<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(0, 0, 0);">(</span>static_method<span style="color: rgb(0, 0, 0);">(</span>Y.<span style="color: rgb(0, 0, 0);">class</span>, "create"<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">0</span>,a<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">1</span>,b<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">2</span>,c<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">)</span>
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
所有的Binder匿名类会被自动生成。
<br>
这叫"do-notation"，是haskell里面用来方便处理monad组合子的利器。
<br>

<br>
在我开发的jaskell语言里面，对do-notation有类似的支持。
<br>

<br>

<br>
题外话：
<br>
最近，看到老庄设计的DJ里面说要支持co。我觉得，如果仅仅象java这样的所谓“支持”，那就和用C的函数指针号称支持OO一样无趣了。
<br>

<br>
一个可以说得上对co有支持的语言，即使不直接支持do-notation，也应该把写匿名类的代价降到和一个lamda函数相接近的程度。
<br>
即使我不能写
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
a &lt;- createA
<br>
b &lt;- createB a
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
也要能够写成：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
createA &gt;&gt;= \a-&gt;createB a</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
组合并不仅仅是几个简单的decorator套起来。真正复杂的co里，不同组合子之间是需要通过bind来通信的。而组合子之间的通信能力才是co强大的根源。</span>
	</td></tr></tbody>
</table>
<img src ="http://www.blogjava.net/ajoo/aggbug/27850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 09:11 <a href="http://www.blogjava.net/ajoo/articles/27850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之八 monad</title><link>http://www.blogjava.net/ajoo/articles/27849.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Fri, 13 Jan 2006 01:08:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27849.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27849.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27849.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27849.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27849.html</trackback:ping><description><![CDATA[<table class="forumline" align="center" border="0" cellpadding="3" cellspacing="1" width="100%">
<tbody><tr><td class="row1" valign="top" width="100%">
	<span class="postdetails">仍然是先用oo把轮廓划出来，我们需要建模一个接口来围绕它进行组合。
<br>

<br>
因为本文是关于co的论述，那么这个接口怎样分析出来的就暂时忽略掉了：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Dependency<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> getArgument<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verifyArgument<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> getProperty<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> key, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verifyProperty<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> key, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
这个Dependency接口由每个不同的组件调用，来解决依赖。如果解析失败，则抛出异常。此处，我们暂时忽略异常这个细节。
<br>

<br>
getArgument负责解析一个函数参数，组件告诉Dependency对象，我需要给第3个参数，类型为String的解析依赖。于是就调用
<br>
getArgument(2, String.class)。
<br>

<br>
getProperty负责解析一个用某个key来标识的属性。比如一个javabean的property。
<br>

<br>
那两个verify是只取得解析到的那个符合要求的组件类型，但是并不实际创建对象。
<br>

<br>

<br>
然后是Component接口。这里，为了名字简短，我们不用ComponentAdapter这么恶长的名字，直接就是Component好了。
<br>

<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
getType()用来返回这个Component生成的对象的类型。
<br>
create用来创建这个对象。
<br>
verify用来保证这个对象可以被创建。
<br>

<br>
至于容器接口，再简单不过了。我们都知道pico不过是个hash table，yan的容器也差不多，虽然多几个getComponentOfType()的方法，但是大体上就是一个hash table。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> <span style="color: rgb(170, 170, 221);">Container</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Component</span> getComponent<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> key<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Component</span> getComponentOfType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
好了。oo完毕。下面来co。
<br>

<br>

<br>
首先，最简单的Component是什么？什么也不干，直接返回一个值。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> ValueComponent <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span> v;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> v==<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span>?<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span>:v.<span style="color: rgb(0, 0, 0);">getClass</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> v;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
稍微难啃点的，是构造函数和工厂方法。这两个都会调用Dependency的getArgument()来取得自己需要的参数实例。
<br>
实际上，java的reflection api里面的Method和Constructor还是有很多相似点的。
<br>
为了抽取共性，我们定义一个新的接口，叫做Function:
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Function<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getReturnType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> getParameterTypes<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> call<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> args<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
这里，我就不展现把Method和Constructor匹配为Function的代码了，因为应该一目了然。
<br>
我们只要知道我们现在可以有三个函数产生Function对象：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> Functions<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Function ctor<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Constructor</span> ctor<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Function method<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> obj, <span style="color: rgb(170, 170, 221);">Method</span> mtd<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Function static_method<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type, <span style="color: rgb(170, 170, 221);">Method</span> mtd<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
当然，还有一些辅助函数，
<br>
比如：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Function ctor<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
然后是FunctionComponent。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> FunctionComponent <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Function f;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> f.<span style="color: rgb(0, 0, 0);">getReturnType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> types = f.<span style="color: rgb(0, 0, 0);">getParameterTypes</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> args = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Object</span><span style="color: rgb(0, 0, 0);">[</span>types.<span style="color: rgb(0, 0, 0);">length</span><span style="color: rgb(0, 0, 0);">]</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">foreach</span><span style="color: rgb(0, 0, 0);">(</span>t:types<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; args<span style="color: rgb(0, 0, 0);">[</span>i<span style="color: rgb(0, 0, 0);">]</span> = dep.<span style="color: rgb(0, 0, 0);">getArgument</span><span style="color: rgb(0, 0, 0);">(</span>i, t<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> f.<span style="color: rgb(0, 0, 0);">call</span><span style="color: rgb(0, 0, 0);">(</span>args<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> types = f.<span style="color: rgb(0, 0, 0);">getParameterTypes</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">foreach</span><span style="color: rgb(0, 0, 0);">(</span>t:types<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> arg_type = dep.<span style="color: rgb(0, 0, 0);">verifyArgument</span><span style="color: rgb(0, 0, 0);">(</span>i, t<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; checkTypeMatch<span style="color: rgb(0, 0, 0);">(</span>types<span style="color: rgb(0, 0, 0);">[</span>i<span style="color: rgb(0, 0, 0);">]</span>, arg_type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> f.<span style="color: rgb(0, 0, 0);">getReturnType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
然后一个基本的component应该是java bean的setter了，对应pico的SetterInjectionComponentAdapter，也对应spring的bean。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> BeanComponent&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> type;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(170, 170, 221);">Object</span> r = createInstance<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; setJavaBeans<span style="color: rgb(0, 0, 0);">(</span>r,dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; ...
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
具体的实现我省略了很多。因为会调用java.beans的api，并且会有一些caching优化的考虑，但是思路上很清楚，就是对每个property调用getProperty()就是了。
<br>

<br>

<br>
好，最基本的就这么几个了（其实，bean component并不是最基本的，后面我们会看到）。
<br>

<br>
下面看看都有些什么组合规则。
<br>

<br>
1。手工指定某个参数。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> WithArgument <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> parent;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> pos;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> arg;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> parent.<span style="color: rgb(0, 0, 0);">getType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> parent.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>withArg<span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> parent.<span style="color: rgb(0, 0, 0);">verify</span><span style="color: rgb(0, 0, 0);">(</span>withArg<span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> Dependency withArg<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Dependency<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> getArgument<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>i==pos<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; checkTypeMatch<span style="color: rgb(0, 0, 0);">(</span>type, arg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> arg.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> dep.<span style="color: rgb(0, 0, 0);">getArgument</span><span style="color: rgb(0, 0, 0);">(</span>i, type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; ...
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
好，通过decorate这个Dependency对象，我们得到了手工制定某个参数的能力。
<br>
这里，我们对参数仍然用Component，而不是一个简单的Object作为这个参数的值，是因为参数本身也可能需要创建，它的依赖关系也可能需要在Dependency对象中解析。如果参数不需要创建，那么，你尽可以用ValueComponent来包装一下。
<br>

<br>

<br>
2。手工指定property的值。跟上面的代码非常类似，就是重载了getProperty()和verifyProperty()。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> WithProperty <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> parent;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span> key;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> prop;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> parent.<span style="color: rgb(0, 0, 0);">getType</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> parent.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>withProp<span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> parent.<span style="color: rgb(0, 0, 0);">verify</span><span style="color: rgb(0, 0, 0);">(</span>withProp<span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> Dependency withProp<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Dependency<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> getProperty<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> k, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>k.<span style="color: rgb(0, 0, 0);">equals</span><span style="color: rgb(0, 0, 0);">(</span>key<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; checkTypeMatch<span style="color: rgb(0, 0, 0);">(</span>type, prop<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> prop.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> dep.<span style="color: rgb(0, 0, 0);">getProperty</span><span style="color: rgb(0, 0, 0);">(</span>k, type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; ...
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
3。和很多组合子一样，map是一个相当有用的组合规则。它负责把一个Component返回的对象作一下额外的处理，transform成另外一个对象。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> <span style="color: rgb(170, 170, 221);">Map</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> map<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> obj<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> MapComponent <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> c;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Map</span> map;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">null</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> map.<span style="color: rgb(0, 0, 0);">map</span><span style="color: rgb(0, 0, 0);">(</span>c.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; c.<span style="color: rgb(0, 0, 0);">verify</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(170, 170, 221);">Object</span>.<span style="color: rgb(0, 0, 0);">class</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; ...
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
注意，这里，因为我们无法预先知道Map这个接口返回的对象会是什么类型，所以，我们让getType()返回null来标示这是一个动态决定的组件类型。
<br>

<br>
4。比map更一般化一点的，是bind动作。所谓bind，也是根据一个Component创建的对象来决定接下来返回什么动作。不同的是，它用这个对象来产生另外一个Component，让这个Component来生成一个新对象。多说无益，让我们看代码：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Binder<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> obj<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> BoundComponent <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> c;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Binder binder;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> getType<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">null</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> binder.<span style="color: rgb(0, 0, 0);">bind</span><span style="color: rgb(0, 0, 0);">(</span>c.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> verify<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; c.<span style="color: rgb(0, 0, 0);">verify</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(170, 170, 221);">Object</span>.<span style="color: rgb(0, 0, 0);">class</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; ...
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
这个Binder接口看似简单，但是它的存在对整个co都是生死攸关的大事。可以说，如果没有这个Binder, co就基本可以不存在了。
<br>
为什么这么说呢？因为这个binder再加上前面的那个ValueComponent代表了一种非常一般性的计算模型：monad。有一个专门的数学分支：组论，就是研究monad的。
<br>
它虽然不是放之四海皆准的计算模型，比如，有比它更为一般性的Arrow模型。但是，用它几乎可以描述我们一般所遇到的大量问题。
<br>

<br>
除了前面的几个基本组合子之外，几乎所有的组合子，如果我们愿意，都可以从这个bind推衍出来。比如上面的map，如果用简洁点的函数式语法来表述的话（原谅我还是忍不住用函数式，java的语法就象一砣一砣屎一样压得我喘不过气来）
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
map<span style="color: rgb(0, 0, 0);">(</span>a, f<span style="color: rgb(0, 0, 0);">)</span> = bind <span style="color: rgb(0, 0, 0);">(</span>a, \x-&gt;value<span style="color: rgb(0, 0, 0);">(</span>f<span style="color: rgb(0, 0, 0);">(</span>x<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
这个代码的意思是说，你可以很轻易地把一个Map对象adapt到Binder对象，只要在bind函数里面调用：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ValueComponent<span style="color: rgb(0, 0, 0);">(</span>map.<span style="color: rgb(0, 0, 0);">map</span><span style="color: rgb(0, 0, 0);">(</span>v<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
就行了。
<br>

<br>
后面的很多组合子，比如对一个组件生成的对象调用某个方法，设置一些java bean setter，都是从这个bind组合子衍生出来的。
<br>

<br>

<br>
好了，今天时间紧迫，到此告一段落吧。</span></td></tr></tbody>
</table>
<img src ="http://www.blogjava.net/ajoo/aggbug/27849.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 09:08 <a href="http://www.blogjava.net/ajoo/articles/27849.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之十一 微步毂纹生</title><link>http://www.blogjava.net/ajoo/articles/27846.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 22:06:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27846.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27846.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27846.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27846.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 最近。age0提出了一个OO设计的问题。因为这个例子更加贴近生活，是我们老百姓所喜闻乐见的商场折扣问题，所以我准备改铉更张用这个例子了。具体的例子请看：http://forum.javaeye.com/viewtopic.php?t=17714&amp;start=0简要的说，需求是： 	  引用:			  有这样一家超市，对顾客实行会员制，...&nbsp;&nbsp;<a href='http://www.blogjava.net/ajoo/articles/27846.html'>阅读全文</a><img src ="http://www.blogjava.net/ajoo/aggbug/27846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 06:06 <a href="http://www.blogjava.net/ajoo/articles/27846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之十 还是重构</title><link>http://www.blogjava.net/ajoo/articles/27845.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:57:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27845.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27845.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27845.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27845.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27845.html</trackback:ping><description><![CDATA[<table class="forumline" align="center" border="0" cellpadding="3" cellspacing="1" width="100%">
<tbody><tr><td class="row1" valign="top" width="100%"><span class="postdetails">已经有点感觉用ioc container来说明co不见得是个好主意了。
<br>
这个container的例子举出来，明显提出意见的人比那个简单的logging例子少了很多。
<br>
毕竟连pico是怎么回事，怎么用，很多人都还不见得了了。更不提多少人对pico的用法就是一个很in的fancy factory。买椟还珠。
<br>

<br>

<br>

<br>
不过，既然开始了，让我还是有始有终吧。
<br>

<br>

<br>
这章还是让我们看看co的refactor。
<br>

<br>
其实，很多人问：怎样把握co里面的基本组合子的度；什么样的组合子算是基本；怎样做到正交；多少的基本组合子才算够用；怎么知道这个组合子会被用到等等。
<br>

<br>

<br>
其实，答案都来自重构。
<br>

<br>
没有谁一下子就作对的。co比起oo，我感觉在设计上反而更容易避免过度设计。
<br>

<br>
为什么？
<br>

<br>
设计oo的时候，你要分析需求，设计各个模块的通信接口，这个过程，同样需要经验，同样需要摸索，同样没有一踀而就的捷径。
<br>

<br>
但是，oo设计的时候又要避免过度，一些时候，在是否通过接口预留灵活性，提取容易变化的部分，或者是尽量简单之间，还是有冲突的。你需要做一个艰难的猜测和抉择。
<br>
而一旦抉择作出，以后如果发现事情进展不如所愿，那么改动接口的代价相当的大。
<br>

<br>

<br>
而如果使用co，在设计简单的各个组合子的时候，你会以一种非常渐进式的方式来发现：哦，原来的组合子设计不够正交，有这个地方可以抽出来，好，抽出来，把波及到的几个组合子的设计修改一下。
<br>

<br>
因为组合子都非常简单，这个变化的波及范围一般来说相当小。
<br>

<br>

<br>
好，空话少说，我们还是看具体例子。
<br>

<br>

<br>
现在，我们发现，除了withArgument, withProperty，我们还希望更灵活地设置参数，比如，我们希望说：
<br>
<ul>对组件X的各个参数，类型为A的，选取以"a1"标识的组件作为参数值，其它的按照缺省方式。
<br>
对组件Y的各个参数，类型为A的，选取以"a2"标识的组件为参数值，其它的按照缺省方式。</ul>
<br>

<br>

<br>
这个需求有几个点：
<br>
<ul>1。需要能够通过key来直接指定某个某个组件，相当于一个"ref"。
<br>
2。需要对参数配置有除了按照参数位置之外的更灵活的配置（比如，按照参数类型）。</ul>
<br>

<br>

<br>
对第一点，我们制作以下的组合子来对应。（看，我们是可以随着需求虽然丰富我们的基本组合子的集合的）
<br>
我们期望做一个UseKey组合子，它可以从容器里面取得另外一个用某个key标识的组件，然后把一切动作都delegate过去。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> UseKey <span style="color: rgb(153, 0, 102); font-weight: bold;">extends</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span> key;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(102, 102, 255);">//?????????</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; ....
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
可是，一开始写代码，就发现，这个代码写不下去！我们需要得到这个容器，才能从这个容器里面取得那个要delegate的组件。可是这个可爱容器对象在哪里呀？
<br>

<br>
仔细分析下来，发现，没有办法。唯一的办法是修改Dependency接口，让它除了帮助解析参数和property之外，再提供给我们当前容器的信息。
<br>

<br>
Dependency接口变为：
<br>

<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Dependency<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> getArgument<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Object</span> getProperty<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> key, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Container</span> getContainer<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
Wow！要改接口了！其实，这一点也不可怕。为什么？
<br>

<br>
co还有另外一个优点我们一直没有提及：细节封装。这个封装不是一般OO意义上的封装，而是说：把要实现的接口细节封装起来，让客户通过预定义好的组合方式来扩展，而不是象oo那样让用户实现实现这个接口来扩展。
<br>

<br>
其实，如果用户使用的都是Component对象，而创建Component对象都是通过：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Container</span>.<span style="color: rgb(0, 0, 0);">getInstance</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Object</span> key<span style="color: rgb(0, 0, 0);">)</span>;
<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
这种方式，那么，Dependency这个接口已经实际上沦为我们的内部实现细节了。用户根本不需要知道存在这么一个接口。
<br>
实际上，当我们的组合子足够丰富之后，完全可以把Dependency接口隐藏在包内部，彻底地对用户屏蔽这个接口。
<br>
如此，客户的扩展完全通过组合Component对象，而不是实现Component接口并且调用Dependency接口。
<br>
不管这个Dependency接口是如何设计的，如何变化，我们都可以把变化隔离在我们包内部，而不会影响用户。
<br>

<br>
好吧。现在假设我们修改了Dependency接口，那么UseKey可以被写为：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> UseKey <span style="color: rgb(153, 0, 102); font-weight: bold;">extends</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Object</span> key;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp;<span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> c = dep.<span style="color: rgb(0, 0, 0);">getContainer</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">getComponent</span><span style="color: rgb(0, 0, 0);">(</span>key<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp;<span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>c==<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span><span style="color: rgb(0, 0, 0);">)</span>throw <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ComponentNotFoundException<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp;<span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> c.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; ....
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>

<br>
然后，更灵活的参数配置。对这个，我们可以借鉴bind操作，做一个对参数的bind。
<br>

<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> ParameterBinder<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
不知道你从Binder接口和ParameterBinder接口看出点什么没有？
<br>
1。Binder, ParameterBinder接口都是给用户去实现的。
<br>
2。这两个接口都不暴露Component的细节，它们的参数和返回值都不涉及Component的接口签名，客户在实现这两个接口的时候，完全不必关心象Dependency接口这种细节。
<br>
3。返回值都是Component，这样，所有的Component组合子都可以被自由使用。
<br>

<br>
实际上，monad组合子就是通过这种方式来在高阶逻辑的层次上隐藏底层细节。
<br>

<br>

<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> ParameterBoundDependency <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Dependency<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Dependency dep;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> ParameterBinder binder;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> getArgument<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> binder.<span style="color: rgb(0, 0, 0);">bind</span><span style="color: rgb(0, 0, 0);">(</span>i, type<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span>dep<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; ...
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
ParameterBoundComponent <span style="color: rgb(153, 0, 102); font-weight: bold;">extends</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> c;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> ParameterBinder binder;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> c.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ParameterBoundDependency<span style="color: rgb(0, 0, 0);">(</span>dep, binder<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; ...
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
用ParameterBinder来做一个Dependency的decorator，问题得到了解决。
<br>

<br>

<br>
然后我们来使用ParameterBoundComponent，为了书写简便，我们假设Component类有一个函数叫做bind
(ParameterBinder binder)。另外Components类有一个useKey(Object
key)函数来生成一个Component对象，用来指向容器内的另外一个组件。
<br>

<br>
于是，上面的需求被实现为：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Component</span> x = ...;
<br>
<span style="color: rgb(170, 170, 221);">Component</span> x2 = x.<span style="color: rgb(0, 0, 0);">bind</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ParameterBinder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>type.<span style="color: rgb(0, 0, 0);">equals</span><span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">useKey</span><span style="color: rgb(0, 0, 0);">(</span>"a1"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(102, 102, 255);">//???? 行1</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
这个x2组件，就是为了实现“当参数类型为A，使用a1，否则使用缺省方式”。
<br>
可是，在行1处，再次遇到了障碍。这个所谓的“缺省方式”，怎么表示？
<br>
。
<br>

<br>
经过思考，我们决定实现一个useArgument(int i, Class type)这样一个组合子，这个组合子可以主动在当前的Dependency对象中选择某个参数作为自己的值。这样，上面的行1就可以写作：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Component</span> x = ...;
<br>
<span style="color: rgb(170, 170, 221);">Component</span> x2 = x.<span style="color: rgb(0, 0, 0);">bind</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ParameterBinder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>type.<span style="color: rgb(0, 0, 0);">equals</span><span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">useKey</span><span style="color: rgb(0, 0, 0);">(</span>"a1"<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">useArgument</span><span style="color: rgb(0, 0, 0);">(</span>i, type<span style="color: rgb(0, 0, 0);">)</span>;<span style="color: rgb(102, 102, 255);">// 行1</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
下面来实现一个UseArgument类：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> UseArgument <span style="color: rgb(153, 0, 102); font-weight: bold;">extends</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Object</span> create<span style="color: rgb(0, 0, 0);">(</span>Dependency dep<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> dep.<span style="color: rgb(0, 0, 0);">getArgument</span><span style="color: rgb(0, 0, 0);">(</span>i, type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; .....
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
哈。完美。一切仍然尽在掌握。
<br>
我们可以以几乎任何方式来customizer组件的参数和property。
<br>

<br>
实际上，如果我们回头看看，甚至可以发现，withArgument(int i, Class type)完全可以用bind(ParameterBinder)来重写：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
<span style="color: rgb(170, 170, 221);">Component</span> withArgument<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Component</span> c, <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span> arg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> c.<span style="color: rgb(0, 0, 0);">bind</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ParameterBinder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> k, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>k==i<span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> arg;
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Components.<span style="color: rgb(0, 0, 0);">useArgument</span><span style="color: rgb(0, 0, 0);">(</span>k, type<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
我们很开心地看到，原来的WithArgument类，WithProperty类都可以扫进垃圾箱了。我们只需要实现更加简单的ParameterBinder接口就可以搞定一切。哈。
<br>

<br>

<br>
同时，希望你也看到了隐藏这些具体的WithArgument，ValueComponent类，而用静态工厂函数withArgument(), value()来代替的好处：
<br>我们可以自由地重构。当发现某个组合子本身并非最简单，而是可以从一些更简单的组合子推演出来，我们只需要改动这些静态工厂函数，而不必告诉用
户：对不起，我的设计改了，不想要WithArgument类了，你能不能改改你的那段new WithArgument(...)的代码？
<br>

<br>

<br>
co让用户只关注接口，而不要管某个功能是直接实现的，还是组合出来的。静态工厂函数提供了对这个细节的封装。
<br>

<br>

<br>
另外一个也许会比较常见的需求，是用一个数组来一次性指定某个组件的所有参数，比如：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
c.<span style="color: rgb(0, 0, 0);">withArguments</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">{</span>c1, c2, c3<span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
这个功能用bind非常非常好实现：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Component</span> withArguments<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">Component</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> args<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ParameterBinder<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">Component</span> bind<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> i, <span style="color: rgb(153, 0, 102); font-weight: bold;">Class</span> type<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> args<span style="color: rgb(0, 0, 0);">[</span>i<span style="color: rgb(0, 0, 0);">]</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>

<br>
当然，你还可以举一反三地提出很多其它的定制参数和property的方法。
<br>

<br>

<br>
好了。今天就到这里。在结束前，我来先提出两个新的需求：
<br>
1。希望对一些用到Logger对象的类注射Logger实例，而这个Logger实例需要用这个使用Logger对象的类对象来创建，这样，这个Logger对象可以静态地知道谁在使用它，而不必每次都构造一个异常来取得StackTrace。
<br>
比如，
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ClassX<span style="color: rgb(0, 0, 0);">(</span>..., Loggers.<span style="color: rgb(0, 0, 0);">instance</span><span style="color: rgb(0, 0, 0);">(</span>ClassX.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>, ...<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table>
<span class="postbody">
<br>
怎样在容器级别全局地规定这个规则呢？我们不知道哪些组件需要注射Logger，也不知道这些组件在哪个参数注射Logger对象。
<br>

<br>
2。怎样提供缺省参数？这样，如果某个参数的需要可以在容器中解析，则拥这个解析出来的实例，否则，使用一个缺省组件。
<br>

<br>
在下一节，我们会通过这两个例子来继续解释co的重构过程。</span>
	</td>
	<td class="row1" align="left" nowrap="nowrap" valign="bottom" width="150">
	  <span class="postdetails"></span>
	<br>
</td>
  </tr>
  <tr>
	<td class="catHead" height="28" width="100%"><span class="topictitle"></span><br>
</td>
	<td class="catHead" height="28" width="100%">&nbsp;&nbsp;&nbsp; <a href="http://forum.javaeye.com/bloglist.php?userid=6423#" onclick="if(confirm('您是否要删除自己的这篇BLOG？')){location='delblog.php?id=2436&userid=6423&treeid=3383';}"><br>
</a></td>
  </tr>
  <tr>
	<td class="row1" colspan="2" align="left" height="26" nowrap="nowrap"><span class="postdetails"></span><br>
</td>
  </tr>
  <tr>
	<td class="row1" valign="top" width="100%"><br>
</td>
	<td class="row1" align="left" nowrap="nowrap" valign="bottom" width="150">
	  <span class="postdetails"><br>
</span>
	</td>
  </tr>
  <tr>
	<td class="catHead" height="28" width="100%"><br>
</td>
	<td class="catHead" height="28" width="100%">&nbsp;&nbsp;&nbsp; <a href="http://forum.javaeye.com/bloglist.php?userid=6423#" onclick="if(confirm('您是否要删除自己的这篇BLOG？')){location='delblog.php?id=2416&userid=6423&treeid=3383';}"><br>
</a></td>
  </tr>
  <tr>
	<td class="row1" colspan="2" align="left" height="26" nowrap="nowrap"><br>
</td>
  </tr>
  <tr>
	<td class="row1" valign="top" width="100%"><br>
</td></tr></tbody>
</table>
<img src ="http://www.blogjava.net/ajoo/aggbug/27845.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:57 <a href="http://www.blogjava.net/ajoo/articles/27845.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之七 重构</title><link>http://www.blogjava.net/ajoo/articles/27844.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:56:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27844.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27844.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27844.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27844.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27844.html</trackback:ping><description><![CDATA[<span class="postdetails">迄今，发现典型的几种疑问是：
<br>
1。组合子的设计要求正交，要求最基本，这是不是太难达到呢？
<br>
2。面对一些现实中更复杂的需求，组合子怎样scale up呢？
<br>

<br>
其实，这两者都指向一个答案：重构。
<br>

<br>

<br>
要设计一个完全正交，原子到不可再分的组合子，也许不是总是那么容易。但是，我们并不需要一开始就设计出来完美的组合子设计。
<br>

<br>
比如，我前面的logging例子，TimestampLogger负责给在一行的开头打印当前时间。
<br>
然后readonly提出了一个新的需要：打印调用这个logger的那个java文件的类名字和行号。
<br>

<br>
分析这个需求，可以发现，两者都要求在一行的开始打印一些东西。似乎有些共性.
<br>
这个"在行首打印一些前缀"就成了一个可以抽象出来的共性.于是重构:
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Factory<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">String</span> create<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> PrefixLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Factory factory;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">boolean</span> freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>;
<br>

<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> prefix<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>freshline<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(170, 170, 221);">Object</span> r = factory.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>r!=<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">print</span><span style="color: rgb(0, 0, 0);">(</span>lvl, r<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">false</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> print<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl, <span style="color: rgb(170, 170, 221);">String</span> s<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; prefix<span style="color: rgb(0, 0, 0);">(</span>lvl<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">print</span><span style="color: rgb(0, 0, 0);">(</span>lvl, s<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl, <span style="color: rgb(170, 170, 221);">String</span> s<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; prefix<span style="color: rgb(0, 0, 0);">(</span>lvl<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>lvl, s<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl, <span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; prefix<span style="color: rgb(0, 0, 0);">(</span>lvl<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>lvl, e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>
这里，Factory接口用来抽象往行首打印的前缀。这个地方之所以不是一个String，是因为考虑到生成这个前缀可能是比较昂贵的（比如打印行号，这需要创建一个临时异常对象）
<br>

<br>
另外，真正的Logger接口，会负责打印所有的原始类型和Object类型，例子中我们简化了这个接口，为了演示方便。
<br>

<br>

<br>
然后，先重构timestamp:
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> TimestampFactory <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Factory<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">DateFormat</span> fmt;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">String</span> create<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> fmt.<span style="color: rgb(0, 0, 0);">format</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Date</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
这样，就把timestamp和“行首打印”解耦了出来。
<br>

<br>

<br>
下面添加TraceBackFactory，负责打印当前行号等源代码相关信息。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> SourceLocationFormat<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(170, 170, 221);">String</span> format<span style="color: rgb(0, 0, 0);">(</span>StackTraceElement frame<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> TraceBackFactory <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Factory<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> SourceLocationFormat fmt;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">String</span> create<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> StackTraceElement frame = getNearestUserFrame<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>frame!=<span style="color: rgb(153, 0, 102); font-weight: bold;">null</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> fmt.<span style="color: rgb(0, 0, 0);">format</span><span style="color: rgb(0, 0, 0);">(</span>frame<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">null</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> StackTraceElement getNearestUserFrame<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> StackTraceElement<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> frames = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Throwable</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">getStackTrace</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">foreach</span><span style="color: rgb(0, 0, 0);">(</span>frame: frames<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>!frame.<span style="color: rgb(0, 0, 0);">getClassName</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">startsWith</span><span style="color: rgb(0, 0, 0);">(</span>"org.<span style="color: rgb(0, 0, 0);">mylogging</span>"<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(102, 102, 255);">//user frame</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> frame;
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">null</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
具体的SourceLocationFormat的实现我就不写了。
<br>

<br>
注意，到现在为止，这个重构都是经典的oo的思路，划分责任，按照责任定义Factory, SourceLocationFormat等等接口，依赖注入等。完全没有co的影子。
<br>

<br>
这也说明，在co里面，我们不是不能采用oo，就象在oo里面，我们也可以围绕某个接口按照co来提供一整套的实现一样，就象在oo里面，我们也可以在函数内部用po的方法来实现某个具体功能一样。
<br>

<br>

<br>
下面开始对factory做一些co的勾当：
<br>
先是最简单的：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> ReturnFactory <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Factory<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">String</span> s;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">String</span> create<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> s;<span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
然后是两个factory的串联，
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> ConcatFactory <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Factory<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Factory<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> fs;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">String</span> create<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(170, 170, 221);">StringBuffer</span> buf = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">StringBuffer</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">foreach</span><span style="color: rgb(0, 0, 0);">(</span>f: fs<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; buf.<span style="color: rgb(0, 0, 0);">append</span><span style="color: rgb(0, 0, 0);">(</span>f.<span style="color: rgb(0, 0, 0);">create</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> buf.<span style="color: rgb(0, 0, 0);">toString</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>

<br>

<br>
最后，我们把这几个零件组合在一起：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
Logger myprefix<span style="color: rgb(0, 0, 0);">(</span>Logger l<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; Factory timestamp = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> TimestampFactory<span style="color: rgb(0, 0, 0);">(</span>some_date_format<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; Factory traceback = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> TraceBackFactory<span style="color: rgb(0, 0, 0);">(</span>some_location_format<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; Factory both = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ConcatFactory<span style="color: rgb(0, 0, 0);">(</span>
<br>
&nbsp; &nbsp; timestamp,
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ReturnFactory<span style="color: rgb(0, 0, 0);">(</span>" - "<span style="color: rgb(0, 0, 0);">)</span>,
<br>
&nbsp; &nbsp; traceback,
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ReturnFactory<span style="color: rgb(0, 0, 0);">(</span>" : "<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> PrefixLogger<span style="color: rgb(0, 0, 0);">(</span>both, l<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
如此，基本上，在行首添加东西的需求就差不多了，我们甚至也可以在行尾添加东西，还可以重用这些factory的组合子。
<br>

<br>
另一点我想说明的是：这种重构是相当局部的，仅仅影响几个组合子，而并不影响整个组合子框架。
<br>

<br>

<br>
真正影响组合子框架的，是Logger接口本身的变化。假设，readonly提出了一个非常好的意见：printException应该也接受level，因为我们应该也可以选择一个exception的重要程度。
<br>

<br>

<br>
那么，如果需要做这个变化，很不幸的是，所有的实现这个接口的类都要改变。
<br>

<br>
这是不是co的一个缺陷呢？
<br>

<br>

<br>
我说不是。
<br>
即使是oo，如果你需要改动接口，所有的实现类也都要改动。co对这种情况，其实还是做了很大的贡献来避免的：
<br>
只有原子组合子需要实现这个接口，而派生的组合子和客户代码，根本就不会被波及到。
<br>
而co相比于oo，同样面对相同复杂的需求，往往原子组合子的数目远远小于实际上要实现的语义数，大量的需求要求的语义，被通过组合基本粒子来实现。也因此会减少直接实现这个接口的类的数目，降低了接口变化的波及范围。
<br>

<br>

<br>
那么，这个Logger接口是怎么来的呢？
<br>

<br>
它的形成来自两方面：
<br>

<br>
1。需求。通过oo的手段分配责任，最后分析出来的一个接口。这个接口不一定是最简化的，因为它完全是外部需求驱动的。
<br>

<br>
2。组合子自身接口简单性和完备性的需要。有些时候，我们发现，一个组合子里面如果没有某个方法，或者某个方法如果没有某个参数，一些组合就无法成立。这很可能说明我们的接口不是完备的。（比如那个print函数）。
<br>
此时，就需要改动接口，并且修改原子组合子的实现。
<br>
因为这个变化完全是基于组合需求的完备性的，所以是co方法本身带来的问题，而不能推诿于oo设计出来的接口。
<br>
也因为如此，基本组合子个数的尽量精简就是一个目标。能够通过基本组合子组合而成的，就可以考虑不要直接实现这个接口。
<br>
当然，这里面仍然有个权衡：
<br>
通过组合出来的不如直接实现的直接，可理解性，甚至可调试性，性能都会有所下降。
<br>
而如果选择直接实现接口，那么就要做好接口一旦变化，就多出一个类要改动这个类的心理准备。
<br>

<br>
如何抉择，没有一定之规。
<br>

<br>
而因为1和2的目标并不完全一致，很多时候，我们还需要在1和2之间架一个adapter以避免两个目标的冲突。
<br>

<br>
比如说，实际使用中，我可能希望Logger接口提供不要求level的println函数，让它的缺省值取INFO就好了。
<br>

<br>
但是，这对组合子的实现来说却是不利的。这时，我们也许就要把这个实现要求的Logger接口和组合子的Logger接口分离开来。（比如把组合子单独挪到一个package中）。
<br>

<br>

<br>

<br>
Logger这个例子是非常简单的，它虽然来自于实际项目，但是项目对logging的需求并不是太多，所以一些朋友提出了一些基于实际使用的一些问题，我只能给一个怎么做的大致轮廓，手边却没有可以运行的程序。
<br>

<br>

<br>
那么，下面一个例子，我们来看看一个我经过了很多思考比较完善了的ioc容器的设计。这个设计来源于yan container。
<br>

<br>

<br>
先说一下ioc容器的背景知识。
<br>

<br>
所谓ioc容器，是一种用来组装用ioc模式（或者叫依赖注射）设计出来的类的工具。
<br>
一个用ioc设计出来的类，本身对ioc容器是一无所知的。使用它的时候，可以根据实际情况选择直接new，直接调用setter等等比较直接的方法，但是，当这样的组件非常非常多的时候，用一个ioc容器来统一管理这些对象的组装就可以被考虑。
<br>

<br>

<br>
拿pico作为例子，对应这样一个类：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> Boy<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Girl girl;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> Boy<span style="color: rgb(0, 0, 0);">(</span>Girl g<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; this.<span style="color: rgb(0, 0, 0);">girl</span> = g;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
...
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
我们自然可以new Boy(new Girl());
<br>

<br>
没什么不好的。
<br>

<br>
但是，如果这种需要组装的类太多，那么这个组装就变成一件累人的活了。
<br>

<br>
于是，pico container提供了一个统一管理组建的方法：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
picocontainer container = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> DefaultContainer<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
container.<span style="color: rgb(0, 0, 0);">registerComponentImplementation</span><span style="color: rgb(0, 0, 0);">(</span>Boy.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
container.<span style="color: rgb(0, 0, 0);">registerComponentImplementation</span><span style="color: rgb(0, 0, 0);">(</span>Girl.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
这个代码，很可能不是直接写在程序里面，而是先读取配置文件或者什么东西，然后动态地调用这段代码。
<br>

<br>
最后，使用下面的方法来取得对象：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">Object</span> obj = container.<span style="color: rgb(0, 0, 0);">getComponentInstance</span><span style="color: rgb(0, 0, 0);">(</span>Boy.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
注意，这个container.getXXX，本身是违反ioc的设计模式的，它<span style="font-weight: bold;">主动</span>地去寻找某个组件了。所以，组件本身是忌讳调用这种api的。如果你在组件级别的代码直接依赖ioc容器的api，那么，恭喜你，你终于成功地化神奇为腐朽了。 <img src="http://forum.javaeye.com/images/smiles/icon_lol.gif" alt="Laughing" border="0"> 
<br>

<br>

<br>
这段代码，实际上应该出现在系统的最外围的组装程序中。
<br>

<br>
当然，这是题外话。
<br>

<br>

<br>
那么，我们来评估一下pico先，
<br>

<br>
1。让容器自动寻找符合某个类型的组件，叫做auto-wiring。这个功能方便，但是不能scale
up。一旦系统复杂起来，就会造成一团乱麻，尤其是有两个组件都符合这个要求的时候，就会出现二义性。所以，必须提供让配置者或者程序员显示指定使用哪个
组件的能力。所谓manual-wire。
<br>
当然，pico实际上是提供了这个能力的，它允许你使用组件key或者组件类型来显示地给某个组件的某个参数或者某个property指定它的那个girl。
<br>

<br>
但是，pico的灵活性就到这里了，它要求你的这个girl必须被直接登记在这个容器中，占用一个宝贵的全局key，即使这个girl只是专门为这个body临时制造的夏娃。
<br>

<br>
在java中，遇到这种情况：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> A createA<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; B b = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> B<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> A<span style="color: rgb(0, 0, 0);">(</span>b,b<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
我们只需要把b作为一个局部变量，构造完A，b就扔掉了。然而，pico里面这不成，b必须被登记在这个容器中。这就相当于你必须要把b定义成一个全局变量一样。
<br>
pico的对应代码：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
container.<span style="color: rgb(0, 0, 0);">registerComponent</span><span style="color: rgb(0, 0, 0);">(</span>"b" <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> CachingComponentAdapter<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ConstructorInjectionComponentAdapter<span style="color: rgb(0, 0, 0);">(</span>B.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
container.<span style="color: rgb(0, 0, 0);">registerComponent</span><span style="color: rgb(0, 0, 0);">(</span>"a", <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ConstructorInjectionComponentAdapter<span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>这里，为了对应上面java代码中的两个参数公用一个b的实例的要求，必须把a登记成一个singleton。
CachingComponentAdapter负责singleton化某个组件，而
ConstructorInjectionComponentAdapter就是一个调用构造函数的组建匹配器。
<br>

<br>

<br>
当然，这样做其实还是有麻烦的，当container不把a登记成singleton的时候（pico缺省都登记成singleton，但是你可以换缺省不用singleton的container。），麻烦就来了。
<br>

<br>
大家可以看到，上面的createA()函数如果调用两次，会创建两个A对象，两个B对象，而用这段pico代码，调用两次getComponentInstance("a")，会生成两个A对象，但是却只有一个B对象！因为b被被迫登记为singleton了。
<br>

<br>

<br>

<br>

<br>

<br>2。pico除了支持constructor injection，也支持setter injection甚至factory method
injection。（对最后一点我有点含糊，不过就假设它支持）。所以，跟spring对比，除了没有一个配置文件，life-cycle不太优雅之
外，什么都有了。
<br>

<br>
但是，这就够了吗？如果我们把上面的那个createA函数稍微变一下：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
A createA<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; B b = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> B<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> A<span style="color: rgb(0, 0, 0);">(</span>b, b.<span style="color: rgb(0, 0, 0);">createC</span><span style="color: rgb(0, 0, 0);">(</span>x_component<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>

<br>
现在，我们要在b组件上面调用createC()来生成一个C对象。完了，我们要的既不是构造函数，也不是工厂方法，而是在某个临时组件的基础上调用一个函数。
<br>

<br>
缺省提供的几个ComponentAdapter这时就不够用了，我们被告知要自己实现ComponentAdapter。
<br>

<br>
实际上，pico对很多灵活性的要求的回答都是：自己实现ComponentAdapter。
<br>

<br>

<br>
这是可行的。没什么是ComponentAdapter干不了的，如果不计工作量的话。
<br>

<br>
一个麻烦是：我们要直接调用pico的api来自己解析依赖了。我们要自己知道是调用container.getComponentInstance("x_component")还是container.getComponentInstance(X.class)。
<br>第二个麻烦是：降低了代码重用。自己实现ComponentAdapter就得自己老老实实地写，如果自己的component
adapter也要动态设置java bean
setter的话，甭想直接用SetterInjectionComponentAdapter，好好看java bean的api吧。
<br>

<br>

<br>
其实，我们可以看出，pico的各种ComponentAdapter正是正宗的decorator pattern。什么CachingComponentAdapter，什么SynchronizedComponentAdapter，都是decorator。
<br>

<br>
但是，这也就是decorator而已了。因为没有围绕组合子的思路开展设计，这些decorator显得非常随意，没有什么章法，没办法支撑起整个的ComponentAdapter的架构。
<br>

<br>
下一章，我们会介绍yan container对上面提出的问题以及很多其他问题的解决方法。
<br>

<br>
yan container的口号是：只要你直接组装能够做到的，容器就能做到。
<br>
不管你是不是用构造函数，静态方法，java bean，构造函数然后再调用某个方法，等等等等。
<br>
而且yan container的目标是，你几乎不用自己实现component adapter，所有的需求，都通过组合各种已经存在的组合子来完成。
<br>

<br>

<br>
对我们前面那个很不厚道地用来刁难pico的例子，yan的解决方法是：
<br>

<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
b_component = Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>B.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">singleton</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
a_component = Components.<span style="color: rgb(0, 0, 0);">ctor</span><span style="color: rgb(0, 0, 0);">(</span>A.<span style="color: rgb(0, 0, 0);">class</span><span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">0</span>, b_component<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; .<span style="color: rgb(0, 0, 0);">withArgument</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">1</span>, b_component.<span style="color: rgb(0, 0, 0);">method</span><span style="color: rgb(0, 0, 0);">(</span>"createC"<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
b_component不需要登记在容器中，它作为局部component存在。
<br>
是不是非常declarative呢？
<br>

<br>

<br>
下一节，你会发现，用面向组合子的方法，ioc容器这种东西真的不难。我们不需要仔细分析各种需求，精心分配责任。让我们再次体验一下吊儿郎当不知不觉间就天下大治的感觉吧。
<br>

<br>
待续。</span><img src ="http://www.blogjava.net/ajoo/aggbug/27844.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:56 <a href="http://www.blogjava.net/ajoo/articles/27844.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之六 oracle</title><link>http://www.blogjava.net/ajoo/articles/27843.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:54:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27843.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27843.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27843.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27843.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27843.html</trackback:ping><description><![CDATA[<span class="postdetails">不少朋友说我的阐述很苍白无力。这让我很苦恼。我确实是拚了命地想把问题说清楚，我也有实际non-trivial的项目经验，怎么就说不明白呢？哎！
<br>

<br>
所以，还是不能不多罗嗦一下，希望能够再阐述得明白一点。
<br>

<br>

<br>
其实，所谓co，有心的朋友也许能够感觉到，它很象是设计一门语言。
<br>
它有顺序/分支，有函数调用，异常处理，基本上一个程序设计语言有的东西它都有了。这些顺序/分支作为语言的基础设施，而一些应对具体需求的原子操作，（比如WriterLogger，比如NeptuneExceptionLogger）则可以看作是语言的扩展或者库。
<br>

<br>
只不过，c/c++/java是有编译器来把源代码转化成目标代码。而co的组合子则是利用了宿主语言（比如java）本身的能力来实现各个组合子的语义。可以说，co是在设计一门语言中的语言。
<br>

<br>

<br>
最近这段时间，流行过一阵LOP（language oriented programming），就是用domain-specific-language来处理一些特定的domain需求。
<br>
为什么会有这种说法呢？还是因为domain的需求多变灵活，不容易琢磨，所以人们发现用一个灵活的语言比用一些功能相对死板的库更容易对付。
<br>
但是dsl的实现不是那么容易的。而co是不是可以说给我们提供了一个相对廉价的创建自己的domain specific language的途径呢?
<br>
我们虽然不能说
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">if</span> level &gt; <span style="color: rgb(0, 0, 0);">1</span> then logger1 <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> logger2</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>
至少可以退而求其次，写出
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
ignore<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">1</span>, logger1, logger2<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>

<br>

<br>

<br>

<br>
当然，这种子语言相比于宿主语言，缺乏调试器的帮助，缺乏编译器的优化，缺乏各种ide的支持，可用性程度是大大不如的。
<br>

<br>
但是，它也有它的好处，那就是，不用额外进行一次编译；写出来的东西和宿主语言无缝集成；可以自动利用宿主语言里面的一切设施。等等。
<br>

<br>
那么如果把co作为一个语言来考虑，是不是会给我们一些别的启示呢？
<br>

<br>
oz曾经质疑，所谓的co，怎样决定基本的组合子？怎么样才知道组合子够用了？
<br>

<br>
那么，设计语言的时候，怎么设计基本的语言设施？怎么样知道这个设施是不足，还是太多呢？
<br>
这是个大话题，语言设计非常有争议性和主观性。但是，也仍然是有些共性的。比如，几乎所有的语言都支持顺序，if/else，递归/循环，函数定义等。相当多我们熟悉的语言还支持异常处理，字符串，整数等。
<br>

<br>
我们难道不能从这里借鉴一些东西？如果我们把基本的nop, 顺序，分支作为启动co的基本要求，这算不算是一个可以遵循的guidline呢？
<br>

<br>
另外，不同的语言，根据它所面向的领域，还有一些不同的内建操作，比如perl，面向文本处理，所以内建了regexp，而c/c++因为直接面对机器硬件模型，所以提供了指针。
<br>
那么，根据我们的组合子所要面对的应用类型，我们也可以预先定义一些内建的原始组合子，比如那个WriterLogger。
<br>

<br>

<br>
一般来说，对general purpose的语言，设计的基础设施都是非常”基础“的，基础到几乎不会有什么设施是多余的。同时，也基础到一般人都可以没有什么困难地掌握基本的语法语义。
<br>
那么这些语言用这么有限的聊聊几个设施怎么对应它不可能预见的各种现实中的需求呢？
<br>

<br>
我们平时对可以用简单的if-else，顺序，循环就可以做几乎任何我们能想到的事情感到惊讶了吗？对某个语言能否处理复杂的需求担忧了吗？
<br>

<br>
为什么没有呢？就在于”组合“的威力。就是那么几个简单的设施，组合起来却可以具有巨大的力量。
<br>

<br>
同样，在设计组合子的时候，如果我们遵循这些共性，同时在和具体需求磨合的时候积极改进组合子本身，应该就可以达到一个可以满意的组合子系统。
<br>

<br>

<br>
说到这里，可能有人问：你不是说组合子系统是脱离需求自己发展的吗？
<br>

<br>

<br>
这个，怎么说呢？还是说语言。设计一个语言，原则上是设计一些和具体需求没有耦合的基础设施，然后让写具体应用的人组合这些基础设施达到我们语言设计者不可能都预见到的某些具体效果。
<br>
但是，在语言设计和逐渐发展过程中，仍然会从用户（就是程序员）那里得到反馈，什么样的需求是他们需要的，什么样的设施不好用，然后设计者再进行改进。
<br>

<br>
一个语言，一般不会是某个具体需求通过划分责任，自顶向下的设计，最后作为这个需求的附属模块被开发出来。更多的情况，是语言的设计者对可能面对的需求有
一个大致了解，并且知道这种可能的需求是变化的，不确定的，于是才会从基本设施开始设计这个语言，最后交付给开发具体应用的人来使用。
<br>

<br>

<br>
组合子系统也遵循一样的规律。组合子的设计需要来自具体需求的灵感和纠正。但是，基本组合子本身却不能耦合于这些具体需求。
<br>
组合子的设计者应该对可能面对的需求有大致的了解，但是并不需要完整地预测这种多变的需求。
<br>

<br>

<br>
当然，组合子这种语言中的语言，还有不容易理解的弱点。当组合层次增多，逻辑变得复杂，这个复杂的组合子可不象写在一般的程序设计语言里面的代码那样简明，java繁琐的语法让这种语言中的语言对一些程序员也许就象是神庙里面的神谕一样难以理解，甚至让人望而生畏。
<br>

<br>
这一半是因为java本身没有提供对这种高阶逻辑的直接支持，组合的语法相对繁琐。如果用haskell，使用语言提供的do-notation，形式上的复杂程度就没了。
<br>

<br>
另一方面，高阶逻辑都是有这种弱点的。
<br>
其实，就算是oo，相比于po，它的多态也是降低可理解性的。
<br>

<br>
因此，就象我们也不能在oo中到处override虚函数一样，组合子的使用也要有一定的度，过犹不及。
<br>

<br>

<br>

<br>
好了，没有实际例子的论述已经太长了。肯定已经有人昏昏欲睡了。
<br>

<br>

<br>
做个调查，我下面的例子有几个选择：
<br>

<br>
<ul>1。简单的predicate。就是一个具有bool is(Object v);方法的接口。
<br>
2。ant的FileSelector。一个predicate的变体。
<br>
3。swing提到的jdbc的action。负责数据库操作的组合子。
<br>
4。yan container的component。负责从任意的构造函数，工厂方法，java bean以及它们的任意组合来产生和注射组件。比pico/spring灵活很多。
<br>
5。neptune的command，负责调用任何ant task以及其它的可能返回一个java对象的函数。是一个一般化了的ant task。</ul>
<br>

<br>

<br>
这些东西都是基于组合子的。大家觉得对哪一个更有兴趣呢？我有些拿不定主意哪个更合适。</span><img src ="http://www.blogjava.net/ajoo/aggbug/27843.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:54 <a href="http://www.blogjava.net/ajoo/articles/27843.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之五 新约</title><link>http://www.blogjava.net/ajoo/articles/27842.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:52:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27842.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27842.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27842.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27842.html</trackback:ping><description><![CDATA[<span class="postdetails">每个小孩刚开始走路的时候都是跌跌撞撞的。
<br>
我们不自量力，妄图踩着上帝的步伐前进。结果就是这么几个简单的象白开水似的类。失望吗？是不是造物试图模仿造物主本身就是一种可笑的狂妄呢？
<br>

<br>
别急，让我们失声痛哭之前先看看我们这几步走的是不是一钱不值。
<br>
<ul><br><span style="font-weight: bold;">1。logger可以把信息打印到log文件中。</span><br><br>
容易，直接创建一个WriterLogger就好了。
<br><span style="font-weight: bold;">
<br>
2。不同的重要程度的信息也许可以打印到不同的文件中？象websphere，有error.log, info.log等。
<br>
如果这样，那么什么重要程度的信息进入error.log，什么进入warning.log，什么进入info.log也需要决定。</span><br><br>
不同的文件吗？好办啊。就是不同的PrintWriter对象了。
<br><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
Logger err_log = writer<span style="color: rgb(0, 0, 0);">(</span>err_writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
Logger warning_log = writer<span style="color: rgb(0, 0, 0);">(</span>warning_writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
Logger info_log = writer<span style="color: rgb(0, 0, 0);">(</span>info_writer<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>

<br>
各个文件记录不同重要程度的信息是么？
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
err_log = filter<span style="color: rgb(0, 0, 0);">(</span>ERROR, err_log, nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
warning_log = filter<span style="color: rgb(0, 0, 0);">(</span>WARNING, warning_log, nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
info_log = filter<span style="color: rgb(0, 0, 0);">(</span>INFO, info_log, nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>
最终把三个不同的logger串联起来就是了：
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
Logger logger = sequence<span style="color: rgb(0, 0, 0);">(</span>err_log, warning_log, info_log<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>

<br>

<br>
<span style="font-weight: bold;">3。也许可以象ant一样把所有的信息都打印到一个文件中。</span>
<br>

<br>
这就更简单了，就一个是WriterLogger。
<br>

<br>

<br>
<span style="font-weight: bold;">4。每条logging信息是否要同时打印当前的系统时间？也是一个需要抉择的问题。</span>
<br>

<br>
拿不定主意是么？没关系，想好了再告诉我。
<br>
反正，如果你需要系统时间，我只需要
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
logger = timestamp<span style="color: rgb(0, 0, 0);">(</span>logger<span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>

<br>

<br>

<br>

<br>
<span style="font-weight: bold;">5。不仅仅是log文件，我们还希望能够在标准错误输出上直接看见错误，普通的信息可以打印到log文件中，对错误信息，我们希望log文件和标准输出上都有。</span>
<br>

<br>
可以创建针对标准输出的Logger，然后和打印log 文件的logger串联起来。
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>

<br>
Logger std_logger = writer<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">err</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
std_logger = ignore<span style="color: rgb(0, 0, 0);">(</span>ERROR, std_logger<span style="color: rgb(0, 0, 0);">)</span>;
<br>
logger = sequence<span style="color: rgb(0, 0, 0);">(</span>std_logger, logger<span style="color: rgb(0, 0, 0);">)</span>;
<br>
</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>

<br>

<br>

<br>

<br>
<span style="font-weight: bold;">6。标准输出上的东西只要通知我们出错了就行，大概不需要详细的stack trace，所以exception stack trace可以打印到文件中，而屏幕上有个简短的exception的message就够了。</span>
<br>

<br>
这里需要对std_logger稍微改写一下：
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(170, 170, 221);">PrintWriter</span> out = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">err</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
std_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ErrorMessageLogger<span style="color: rgb(0, 0, 0);">(</span>out, writer<span style="color: rgb(0, 0, 0);">(</span>out<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
std_logger = ignore<span style="color: rgb(0, 0, 0);">(</span>ERROR, std_logger, nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>
用ErrorMessageLogger来改写对异常的log逻辑。
<br>

<br>

<br>

<br>
<span style="font-weight: bold;">7。warning似乎也应该输出到屏幕上。</span>
<br>

<br>
好啊。就是把ignore函数里面的ERROR换成WARNING就好了
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
std_logger = ignore<span style="color: rgb(0, 0, 0);">(</span>WARNING, std_logger, nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>

<br>

<br>
<span style="font-weight: bold;">8。不管文件里面是否要打印当前系统时间，屏幕上应该可以选择不要打印时间。</span>
<br>

<br>
对std_logger不掉用timestamp就是了。
<br>
<span style="font-weight: bold;">
<br>
9。客户应该可以通过命令行来决定log文件的名字。</span>
<br>

<br>
这条和logger组合子其实没什么关系。
<br>

<br>
<span style="font-weight: bold;">10。客户可以通过命令行来决定log的细节程度，比如，我们只关心info一样级别的信息，至于debug, verbose的信息，对不起，不要打印。</span>
<br>

<br>
生成那个最终使用的Logger对象的时候，再ignore一下就行了：
<br>

<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
logger = ignore<span style="color: rgb(0, 0, 0);">(</span>some_level, logger, nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>

<br>
<span style="font-weight: bold;">
<br>
11。neptune生成的是一些Command对象，这些对象运行的时候如果出现exception，这些exception会带有execution
trace，这个execution trace可以告诉我们每个调用栈上的Command对象在原始的neptune文件中的位置（行号）。
<br>
这种exception叫做NeptuneException，它有一个printExecutionTrace(PrintWriter)的方法来打印execution trace。
<br>
所以，对应NeptuneException，我们就不仅仅是printStackTrace()了，而是要在printStackTrace()之前调用printExecutionTrace()。</span>
<br>

<br>
NeptuneExceptionLogger就是给这个准备的呀。
<br>
<span style="font-weight: bold;">
<br>12。neptune使用的是jaskell语言，如果jaskell脚本运行失败，一个EvaluationException会被抛出，这个
类有一个printEvaluationTrace(PrintWriter)的方法来打印evaluation
trace，这个trace用来告诉我们每个jaskell的表达式在脚本文件中的位置。
<br>
所以，对应EvaluationException，我们要在printStackTrace()之前，调用printEvaluationTrace()。</span>
<br>

<br>
JaskellExceptionLogger
<br>

<br>
<span style="font-weight: bold;">
<br>
13。execution trace和evaluation trace应该被打印到屏幕上和log文件两个地方。</span>
<br>

<br>
这就是说，上面两个Logger应该被应用到std_logger和logger两个对象中。
<br>
<span style="font-weight: bold;">
<br>

<br>
14。因为printExecutionTrace()和printEvaluationTrace()本身已经打印了这个异常的getMessage()，所以，对这两种异常，我们就不再象对待其它种类的异常那样在屏幕上打印getMessage()了，以免重复。 </span>
<br>

<br>
就是说，一旦一个exception被发现是NeptuneException，那么ErrorMessageLogger就要被跳过了。
<br>
</span><table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">
<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger err_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ErrorMessageLogger<span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger jaskell_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> JaskellExceptionLogger<span style="color: rgb(0, 0, 0);">(</span>writer, err_logger<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger neptune_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> NeptuneExceptionLogger<span style="color: rgb(0, 0, 0);">(</span>writer, jaskell_logger<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> neptune_logger;</div>
<br>
</td>
	</tr>
</tbody></table><span class="postbody">
<br>这个neptune_logger先判断异常是不是NeptuneException，如果是，直接处理，否则，传递给
jaskell_logger。jaskell_logger继续判断，如果不是它感兴趣的，再传递给ErrorMessageLogger来做最后的缺
省处理。
<br>

<br>
<span style="font-weight: bold;">
<br>
15。也许还有一些暂时没有想到的需求， 比如不是写入log文件，而是画个图之类的变态要求</span>。
<br>

<br>
放马过来吧。看我们的组合子能不能对付。
<br>
</span></ul>
<br>

<br>
很惊讶地发现，就这么几个小儿科似的积木，就似乎全部解决了曾让我们烦恼的这些需求？
<br>

<br>
为了给大家一个完整的印象，下面是我实际项目中使用这些组合子应对上面这些需求的代码：
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> StreamLogger <span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">OutputStream</span> out;
<br>
&nbsp;
<br>
&nbsp; <span style="color: rgb(102, 102, 255);">/**
<br>
&nbsp; &nbsp;* To create a StreamLogger object.
<br>
&nbsp; &nbsp;* @param out the OutputStream object that the log message should go to.
<br>
&nbsp; &nbsp;*/</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> StreamLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">OutputStream</span> out<span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; this.<span style="color: rgb(0, 0, 0);">out</span> = out;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp;
<br>
&nbsp; <span style="color: rgb(102, 102, 255);">/**
<br>
&nbsp; &nbsp;* To get the OutputStream that the log messages should go to.
<br>
&nbsp; &nbsp;*/</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(170, 170, 221);">OutputStream</span> getStream<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span> <span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> out;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger getBaseLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">PrintWriter</span> writer<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger nop = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> NopLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger base = Loggers.<span style="color: rgb(0, 0, 0);">logger</span><span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger neptune_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> NeptuneExceptionLogger<span style="color: rgb(0, 0, 0);">(</span>writer, nop<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger jaskell_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> JaskellExceptionLogger<span style="color: rgb(0, 0, 0);">(</span>writer, nop<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Loggers.<span style="color: rgb(0, 0, 0);">sequence</span><span style="color: rgb(0, 0, 0);">(</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Logger<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">{</span>neptune_logger, jaskell_logger, base<span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger getEchoLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">PrintWriter</span> writer<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ErrorMessageLogger<span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger getErrorLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">PrintWriter</span> writer<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger err_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> ErrorMessageLogger<span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger jaskell_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> JaskellExceptionLogger<span style="color: rgb(0, 0, 0);">(</span>writer, err_logger<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger neptune_logger = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> NeptuneExceptionLogger<span style="color: rgb(0, 0, 0);">(</span>writer, jaskell_logger<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> neptune_logger;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(102, 102, 255);">/**
<br>
&nbsp; &nbsp;* Get the Logger instance.
<br>
&nbsp; &nbsp;* @param min_level the minimal critical level for a log message to show up in the log.
<br>
&nbsp; &nbsp;* @return the Logger instance.
<br>
&nbsp; &nbsp;*/</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> Logger getDefaultLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> min_level<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> writer = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span><span style="color: rgb(0, 0, 0);">(</span>out, <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> err = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">err</span>, <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> warn = <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">out</span>, <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger all = Loggers.<span style="color: rgb(0, 0, 0);">sequence</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> Logger<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; &nbsp; Loggers.<span style="color: rgb(0, 0, 0);">ignore</span><span style="color: rgb(0, 0, 0);">(</span>getErrorLogger<span style="color: rgb(0, 0, 0);">(</span>err<span style="color: rgb(0, 0, 0);">)</span>, Logger.<span style="color: rgb(0, 0, 0);">ERROR</span><span style="color: rgb(0, 0, 0);">)</span>,
<br>
&nbsp; &nbsp; &nbsp; &nbsp; Loggers.<span style="color: rgb(0, 0, 0);">filter</span><span style="color: rgb(0, 0, 0);">(</span>getEchoLogger<span style="color: rgb(0, 0, 0);">(</span>warn<span style="color: rgb(0, 0, 0);">)</span>, Logger.<span style="color: rgb(0, 0, 0);">WARNING</span><span style="color: rgb(0, 0, 0);">)</span>,
<br>
&nbsp; &nbsp; &nbsp; &nbsp; getBaseLogger<span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> Loggers.<span style="color: rgb(0, 0, 0);">ignore</span><span style="color: rgb(0, 0, 0);">(</span>all, min_level<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
为了偷懒，我没有用配置文件，就是把这些策略硬编码进java了。好在上面的代码非常declarative，改起来也很容易。
<br>

<br>
没习惯读代码的朋友。这里奉劝还是读一读吧。很多时候，代码才是说明问题的最好手段。我相信，只有读了代码，你才能真正尝到CO的味道。
<br>

<br>

<br>
有朋友问，你这个东西和decorator pattern有什么区别呀？乍看上去，还真是长得差不多呢。不都是往现有的某个对象上面附加一些功能吗？
<br>
也许是把。我不知道象SequenceLogger这种接受一个数组的，是否也叫做对数组的decorator；也不知道IgnoreLogger接受了两个Logger对象，这个decorator究竟是修饰谁的呢？
<br>

<br>
其实，叫什么名字无所谓。我这里要讲的，是一种从基本粒子推演组合的思路。形式上它也许碰巧象decorator, 象ioc。但是正如workinghard所说（这句话深得我心），思路的切入点不同。
<br>

<br>
如果你仔细看上面的代码，也许你会有所感觉：对Logger的千奇百怪的组合本身已经有点象一个程序代码了。
<br>
如果用伪码表示：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
&nbsp; all_logger = ignore messages below ERROR <span style="color: rgb(153, 0, 102); font-weight: bold;">for</span><span style="font-weight: bold;"> </span>getErrorLogger<span style="color: rgb(0, 0, 0);">(</span>err<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filter messages except WARNING <span style="color: rgb(153, 0, 102); font-weight: bold;">for</span> getEchoLogger<span style="color: rgb(0, 0, 0);">(</span>warn<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; baseBaseLogger<span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; ignore messages below lvl <span style="color: rgb(153, 0, 102); font-weight: bold;">for</span> all_logger;</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>
当组合子越来越多，需求越来越复杂，这个组合就会越来越象个程序。
<br>

<br>
这里，实际上，（至少我希望如此），我们的思维已经从打印什么什么东西上升为在Logger这个级别的组装了。
<br>

<br>
这也就是所谓higher order logic的意思。
<br>

<br>

<br>
所谓combinator-oriented，在这里，就体现为系统性地在高阶逻辑的层面上考虑问题，而不是如decorator那样的零敲碎打的几个功能模块。
<br>
大量的需求逻辑被以声明式的方式在高阶逻辑中实现，而基本的组合子只负责实现原字操作。
<br>

<br>

<br>
当然，缺点也是明显的，对此我不讳言：
<br>

<br>
<ul>高阶逻辑不容易调试，当我们使用一个组合了十几层的复杂的Logger对象的时候（真正用了co这种情况不少见），一旦出现bug，跟踪的时候我们就会发现象是陷入了一个迷宫，从一个组合子跟踪进入另一个组合子，绕来绕去。
<br><br>
另外，异常的stack trace也无法反映组合层次关系，造成错误定位麻烦。</ul>
<br>

<br>

<br>
这也许不是co本身的问题，而是因为java这种oo语言对co没有提供语言上的支持。但是无论如何，这对在java中大规模使用co造成了障碍。
<br>

<br>
也许你还无法理解。平时我们在java中用那么几个decorator，本身非常简单，所以debug, trace都不是问题。可是，一旦oriented起来，情况就不同了。街上有两辆车和成千上万辆车，对交通造成的压力截然不同。
<br>

<br>

<br>
还有朋友，对co如何把握有疑问。难道co就是瞎猫碰死耗子么？
<br>

<br>
其实，无论co还是oo，对设计者都是有一定要求的。
<br>
oo要求你了解需求，并且经验丰富，也要有一点点运气。
<br>
co也要求经验，这个经验是设计组合子系统的经验。什么样的组合子是好的？怎么才算是足够简单？什么组合规则是合理的？等等，这些，也有规律可循，就像oo的各种模式一样。同时，也可以refactor。毕竟，怎么简单地想问题比怎么分解复杂问题可能还是要容易掌握一点。
<br>

<br>
不过，co对经验的要求稍微小一点，但是对数学和逻辑的基本功要求则多了一点。有了一些数学和逻辑方面的基本功，那么设计组合子就会轻松的多。
<br>

<br>
co也要有一点点运气。所以遇到你怎么想也想不明白的情况，就别死抗啦，也许这个问题就抽象不出组合子来，或者以我们普通人的智慧抽象不出来。
<br>

<br>

<br>

<br>
co是银弹吗？当然不是，至少以我的功力没有这种自信。
<br>
遇到复杂的问题我也是先分解需求，面向接口的。只有问题的规模被控制在了一定的范围，我才会试图用co来解决问题。靠着对co的一些经验和感觉，一旦发现了可以组合子化的概念，成果会非常显著。
<br>

<br>

<br>而且，co和oo关注的层面也不同。co是针对一个单独的概念（这点倒有点象ao），一点一点演绎，构成一个可以任意复杂的系统，一个好的co也
会大大减少需要引入的概念数。而oo是处理大量互相或者有联系，或者没有联系的概念，研究怎么样把一个看上去复杂的系统的复杂度控制住。所以两者并不是互
相排斥的。自顶向下，自底向上，也许还是两手一起抓更好些。
<br>

<br>
这段时间应用co做了几个软件后，感觉co最擅长的领域是：
<br>
问题域有比较少的概念，概念简明清晰（比如logger, predicate, factory，command），但是对概念的实现要求非常灵活的场合。
<br>
这种时候，用oo就有无处下嘴之感。毕竟概念已经分解了，职责也清楚，就是怎么提供一个可以灵活适应变化的体系，而对这个，oo并没有提供一个方法论。基本上就是用po的方法吭哧吭哧硬做。而co此时就可以大展用武之地。弥补这个空隙。
<br>

<br>

<br>

<br>
看过圣经的，也许有感觉，旧约里面的上帝严厉，经典，就像是一个纯粹的fp语言，每个程序员都被迫按照函数式，组合子的方式思考问题，你感觉困难？那是你不够虔诚。你们人不合我的心意，我淹死你们！
<br>

<br>

<br>
而新约里面，明显添加了很多人情味儿。上帝通过自己的儿子和人们和解了。既然淹死一波，再来一波还是这样，那么是不是说大家应该各让一步呢？
<br>co和oo，既然各自都不能宣称自己就是银弹，那么为什么不能拉起手来呢？我们不是神，不可能真正按照神的方式用基本粒子组合演化世界，所以就别
象清教徒一样苦苦追求不可能的目标了。但是，上帝的组合之道毕竟相当巧妙，在有些时候荆棘里面出现火焰的时候，我们又何必固执地拒绝造物主的好意呢？礼貌
地说一声：“谢了！老大”。不是皆大欢喜？
<br>

<br>

<br>
这一节我们继续讲解了这个logging的例子。实际上，logging是一个非常简单的组合子，下面如果大家对这个例子有疑问，我会尽力解答。
<br>

<br>
然后，我们会进军下一个例子。</span><img src ="http://www.blogjava.net/ajoo/aggbug/27842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:52 <a href="http://www.blogjava.net/ajoo/articles/27842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之四 燃烧的荆棘</title><link>http://www.blogjava.net/ajoo/articles/27841.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:46:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27841.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27841.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27841.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27841.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27841.html</trackback:ping><description><![CDATA[<span class="postdetails">唧唧歪歪一大堆。肯定早有人不耐烦了。
<br>
"你丫还有没有点实在的东西呀？"
<br>
要是我，可能也早就忍不住了。
<br>

<br>
好，好。我其实并没有忘记前面说的那个logging的例子。卖了这么长时间的关子，除了有想形而上的虚荣心外，也是想给大家多一点时间来嚼一下这个例子，让熟悉OO的朋友肚子里面多少有个腹稿。
<br>

<br>
下面，我来继续上回书说到的这个logging。
<br>

<br>
前面列举了那么一大堆乱七八糟的需求，不知道是不是有人和我一样看着这些繁杂的条目闹心。我在做的时候其实只想了五六条需求，就已经开始烦了。何况还有一
些暂时不知道如何抉择的几个疑问点。最初Kiss出来的那个logger实现明显不能用了。refactor的价值也有限。
<br>

<br>
怎么办？智慧果也许给了我们智慧，但是这智慧毕竟是有限的。侧头看去，蓦然看见荆棘里跳动的火焰，那是上帝的光芒么？
<br>

<br>
好，既然这条路看来比较坎坷，换条路试试看也未尝不可。走这条路的好处在于，我们可以暂时不用理会这些讨厌的“需求”了。CO这个方法论不是以需求为中心，而是从底层的组合子出发，就像小孩子摆弄积木，我们只管发挥自己的想象力，看看我们能摆弄出些什么东西来就好了。
<br>

<br>

<br>
如果一切顺利，我们希望能够跨越瀚海高山，走到流着奶和蜜的土地。所有这些乱七八糟的需求，我们希望他们能够被简单地配置，或者至少能够通过声明式的方法来“声明”，而不是通过过程式的方法来“实现”。
<br>

<br>
出发之前，鼓舞以下士气先。
<br>
前面charon说，这种东西类似公理系统。确实，非常非常类似。不过，门槛并不像这个名字听来那么吓人的高。我们并不需要一下子就完全把完备性考虑清楚，我们不是上帝，没有这么大本事。
<br>

<br>
类似于xp + refactoring，我们的组合子的建造也一样可以摸着石头过河，走一步看一步的。
<br>

<br>
比如，假如我的Logger接口定义的时候没有print函数而只有println，那么后面我们会发现在制造打印当前时间的组合子的时候会出现麻烦。不过，没关系，等到意识到我们需要一个print()函数的时候，回过头来refactor也是可以的。
<br>

<br>

<br>
为了说明这点，我们现在假设Logger接口是这样：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
好，路漫漫而修远兮，我们就这样按照上帝的昭示上路吧，虽然前路云封雾锁。
<br>

<br>

<br>

<br>
首先，任何组合子系统的建立，都起步于最最基本最最简单的组合子。然后再一步步组合。
<br>

<br>
比如，布尔代数必然起步于true和false；自然数起步于0，1，然后就可以推演出整个系统。
<br>

<br>
那么，对Logger来说，有0和1吗？
<br>

<br>
有的。
<br>

<br>
0就是一个什么都不做的Logger。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> NopLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
（注，不要小看这个什么都不做的Logger，它的作用大着呢。你能想象一个没有0的整数系统吗？）
<br>

<br>
什么是1呢？一个直接向文件中打印信息的应该就是一个1了。
<br>
伪码如下：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> FileLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; write msg to log file.
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; write exceptioon to log file.
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>
那么，怎么实现这个类呢？
<br>

<br>
这里，我们遇到一个东西要抉择，文件打开是要关闭的。那么谁负责打开文件？谁负责关闭？是否要在构造函数中new FileOutputStream()？，然后再提供一个close()函数来close这个stream？
<br>

<br>
答案是：不要。
<br>

<br>
无论是ioc也好，还是CO的组合方法也好，一个原则就是要尽量保持事情简单。那么，什么最简单？我们此处真正需要的是什么？一个file么？
<br>
不，其实一个PrintWriter就足够了。
<br>
当然，最终文件必须还是要通过代码打开，关闭。但是，既然反正也要打开文件，我们这里不去管也不会增加什么工作量，对么？那么为什么不乐得清闲呢？
<br>
“先天下之忧而忧”这种思想是最最要不得的。
<br>

<br>

<br>
于是，最简单的1应该是这样：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> WriterLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> writer;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; writer.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; e.<span style="color: rgb(0, 0, 0);">printStackTrace</span><span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; WriterLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">PrintWriter</span> writer<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp;this.<span style="color: rgb(0, 0, 0);">writer</span> = writer;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
“哈！还说什么CO。你这不是剽窃ioc pattern吗？”
<br>
完了，被抓个现形。还真是ioc pattern。其实，世界上本来没有什么新东西，所谓“方法论”，本来是一种思考方法，而不是说形式上必然和别人不同。不过，说我剽窃，我就剽窃吧。
<br>

<br>

<br>
好。最简单的原子写出来了。希望到现在，你还是会觉得：“介，介有什么呀？”
<br>

<br>

<br>
下面来看组合规则。都可以弄些什么组合规则呢？让我来掰着脚指头数一数。
<br>
有一点作为thumb of rule需要注意的：每个组合规则尽量简单，并且<span style="font-weight: bold;">只做一件事</span>。
<br>

<br>
1。顺序。把若干个logger对象顺序写一遍，自然是一种组合方式。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> SequenceLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">foreach</span><span style="color: rgb(0, 0, 0);">(</span>l: loggers<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; l.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">foreach</span><span style="color: rgb(0, 0, 0);">(</span>l:loggers<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; l.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> loggers;
<br>
&nbsp; SequenceLogger<span style="color: rgb(0, 0, 0);">(</span>Logger<span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">]</span> ls<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; this.<span style="color: rgb(0, 0, 0);">loggers</span> = ls;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>

<br>
2。逻辑分支。当消息的重要程度等于某一个级别的时候，写logger1，否则写logger2。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> FilteredLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger1;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger2;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>level==lvl<span style="color: rgb(0, 0, 0);">)</span>logger1.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> logger2.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>lvl==ERROR<span style="color: rgb(0, 0, 0);">)</span> logger1.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> logger2.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>
为了简洁，下面的例子我就不写构造函数了。
<br>

<br>

<br>
3。忽略。当消息的重要程度大于等于某一个值的时候，我们写入logger1，否则写入logger2。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> IgnoringLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger1;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger2;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>level&gt;=lvl<span style="color: rgb(0, 0, 0);">)</span>logger1.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> logger2.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>lvl&lt;=ERROR<span style="color: rgb(0, 0, 0);">)</span> logger1.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span> logger2.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
其实，2和3本来可以统一成一个组合规则的，都是根据消息重要程度来判断logger走向的。如果我用的是一个函数式语言，我会毫不犹豫地用一个predicate函数来做这个抽象。
<br>
可惜，java中如果我要这么做，就要引入一个额外的interface，还要多做两个adapter来处理ignore和filter，就为了节省一个类和几行代码，这样做感觉不是很值得，所以就keep it stupid了。
<br>

<br>

<br>

<br>
对了。我说“CO不看需求”了么？如果说了，对不起，我撒谎了。
<br>
CO确实不是一个以需求为中心的方法论。它有自己的组合系统要关心。
<br>
但是需求也仍然在CO中有反映。我们前面提出的那些需求比如打印系统时间什么的不会被无中生有地实现。
<br>
只不过，在CO里面，这些需求不再影响系统架构，而是被实现为一个一个独立的组合子。同时，我们抛开需求之间复杂的逻辑关系，上来直奔主题而去就好了。
<br>

<br>
4。对exception直接打印getMessage()。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> ErrorMessageLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> out;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp;logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp;out.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>e.<span style="color: rgb(0, 0, 0);">getMessage</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
5。对了，该处理NeptuneException了。如果一个exception是NeptuneException，打印execution trace。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> NeptuneExceptionLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> out;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>e instanceof NeptuneException<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">(</span>NeptuneException<span style="color: rgb(0, 0, 0);">)</span>e<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">printExecutionTrace</span><span style="color: rgb(0, 0, 0);">(</span>out<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
6。对EvaluationException，照猫画虎。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> JaskellExceptionLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span> out;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>e instanceof EvaluationException<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">(</span>EvaluationException<span style="color: rgb(0, 0, 0);">)</span>e<span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">printEvaluationTrace</span><span style="color: rgb(0, 0, 0);">(</span>out<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
7。在每行消息前打印系统时间。
<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> TimestampLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>level, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Date</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">toString</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>+": " + msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>ERROR, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Date</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">toString</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>+": "<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>
这个类其实可以再注射近来一个DateFormat来控制日期格式。但是这不是重点，我们忽略掉了它。
<br>
可是，这个类有一个很别扭的地方，在printException中，我们必须要把系统时间单独打印在一行，然后再打印异常信息。
<br>

<br>
这可不是我们想要的效果。我们本来是想让系统时间出现在同一行的。
<br>
怎么办？回头看看，如果Logger接口多一个print函数，一切就迎刃而解了。重构。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> TimestampLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">final</span> Logger logger;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">boolean</span> freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">private</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printTimestamp<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">if</span><span style="color: rgb(0, 0, 0);">(</span>freshline<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">print</span><span style="color: rgb(0, 0, 0);">(</span>level, <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">Date</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>.<span style="color: rgb(0, 0, 0);">toString</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>+": "<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> print<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; printTimestamp<span style="color: rgb(0, 0, 0);">(</span>level<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">print</span><span style="color: rgb(0, 0, 0);">(</span>level, msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">false</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; printTimestamp<span style="color: rgb(0, 0, 0);">(</span>level<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; printTimestamp<span style="color: rgb(0, 0, 0);">(</span>ERROR<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; logger.<span style="color: rgb(0, 0, 0);">printException</span><span style="color: rgb(0, 0, 0);">(</span>e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; &nbsp; freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
当然，前面的一些组合子也都要增加这个print函数。相信这应该不难。就留给大家做个练习吧。
<br>

<br>

<br>
好啦。到现在，我们手里已经有两个基本组合子，7个组合规则。应该已经可以组合出来不少有意义没意义的东西了。
<br>

<br>
为了避免写一大堆的new和冗长的类名字，我们做一个facade类，来提供简短点的名字，节省我们一些键盘损耗。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> Loggers<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger nop<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span><span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> NopLogger<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;<span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger writer<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">PrintWriter</span> writer<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> WriterLogger<span style="color: rgb(0, 0, 0);">(</span>writer<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger writer<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">OutputStream</span> out<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> writer<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> <span style="color: rgb(170, 170, 221);">PrintWriter</span><span style="color: rgb(0, 0, 0);">(</span>out, <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger filter<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl, Logger l1, Logger l2<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">return</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">new</span> FilteredLogger<span style="color: rgb(0, 0, 0);">(</span>lvl, l1, l2<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger ignore<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>...<span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">static</span> Logger timestamp<span style="color: rgb(0, 0, 0);">(</span>...<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>...<span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; ...
<br>
<span style="color: rgb(0, 0, 0);">}</span></div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
这样，在用这些组合子的时候大概代码能够好看一点吧。
<br>

<br>

<br>
好了，走了这么远，（虽然很多人可能还是觉得根本没看见什么激动人心的东西吧？都是简单得不能再简单的小类，有什么了不起的呢？）。让我们停下脚步，看看这么信马由缰把我们带到了哪里吧。
<br>

<br>

<br>
下一回，我们会试着用这些组合子和组合规则来看看能不能对付前面提出的那些乱七八糟的需求。</span><img src ="http://www.blogjava.net/ajoo/aggbug/27841.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:46 <a href="http://www.blogjava.net/ajoo/articles/27841.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之三 失乐园 之补充</title><link>http://www.blogjava.net/ajoo/articles/27840.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:43:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27840.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27840.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27840.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27840.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27840.html</trackback:ping><description><![CDATA[<span class="postdetails">失乐园发了之后。有的朋友对“OO是一种自顶向下的方法论”的论述有些疑问。
<br>

<br>
这里补充一下。
<br>

<br>
如果认可OO是一个责任分配体系，那么自顶向下就是一个自然的逻辑结论。
<br>

<br>

<br>
没有分析出来“需求”，也就无所谓“责任”，于是根本就无所谓“OO”了。
<br>

<br>
这种从分析需求，分解需求，分配责任，再分析子需求，分解子需求，在子模块内分配责任的方式，被我称为“自顶向下”。
<br>

<br>

<br>
至于说xp, tdd和自顶向下是不矛盾的。它们也都是要依赖于需求分析的。test case是什么?不就是需求么?
<br>
当然，这些方法论并不要求需求百分之百的细化，它们认可变化，拥抱变化，力求变化时的代价最小。不过，不管怎么说，它们仍然是要着眼于当前的需求的，应对需求变化的能力是另外一个话题，它并不能表示这些方法论不是自顶向下。
<br>

<br>
“自底向上”确实古已有之，PO时代也确实有这个提法。但是，它的缺乏方向性，缺乏重用能力，缺乏整体组织等等弊病让它从来都没有成为设计的主流，没有成为一个主导整体或者部分设计的思想。
<br>
最多算是公有制体制内的私有制补充而已。PO时代它的地位就不高，到了OO时代，强调职责分配，它更是几乎沦为一个历史词汇了。
<br>

<br>

<br>
也许你会说，我在调用xcerces, stl的时候，难道也是自顶向下？我可从来没有给stl的作者分配过责任啊。
<br>

<br>
这其实和责任分配并不矛盾。中间如果发现可以重用的模块，只要这个模块向外承诺的责任符合我的期望，我就可以用。仍然是自顶向下，需求驱动，责任驱动。
<br>
而且，xcerces这些库设计的时候，也一样要假想一下需求，然后从需求出发的。（stl不是很一样，它一定程度上有CO的影子，从基本组合子逐渐演绎的方法在其中也有体现，比如那个iterator和所有围绕iterator的算法等）</span><img src ="http://www.blogjava.net/ajoo/aggbug/27840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:43 <a href="http://www.blogjava.net/ajoo/articles/27840.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之二 失乐园</title><link>http://www.blogjava.net/ajoo/articles/27839.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:29:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27839.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27839.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27839.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27839.html</trackback:ping><description><![CDATA[<span class="postdetails">前面我们讲到一些OO和CO的区别。肯定有人不以为然。什么CO？OO包罗万象，你所谓的CO也不过是OO的一个分支而已。
<br>

<br>

<br>
是啊，易经也包罗万象，也许太极图或者伏羲六十四卦早就可以描述蒸汽机，喷气战斗机，计算机，烤火鸡，等等，更何况什么OO，CO呢？
<br>

<br>
其实，如果把OO当作一个大箩筐，什么都往里装，自然，我这里要说的也不会跳出它的藩篱。毕竟我这CO还是用java实现的呢，归根结底，不是还要用class, interface之类的东西乱搞？
<br>

<br>
而我所谈的OO，和老庄不同，不是那么一个宽泛的概念。实际上，我说的OO包括两个阶段。
<br>

<br>
第一个阶段：
<br>
<ul>1。认识到数据和行为的统一性。用类来封装数据，隐藏数据，并且对行为建模。这种更高级的ADT应该是OO的最基本形态。
<br>
2。用类继承的方式来渐进式地描述现实生活中的概念。对概念之间的差别用子类覆盖父类某一个方法的途径来表达。</ul>
<br>

<br>
在这个阶段，传统的“封装，继承，多态”就已经被提了出来。
<br>

<br>
这种看上去很美的非常符合人的直觉的方法被人们很快地接受了。
<br>

<br>
毕竟，Person, Vehicle, Animal等等做成类是多么直白，vehicle.start(), person.work(), animal.eat()看上去是多么简单。
<br>
人们象吃了善恶果一样发现眼睛似乎一下子明亮了，世界看上去竟然那么分明。靠，老子怎么没早知道有这个果子？还有没有？再给两个！
<br>

<br>
但是，真正应用到变化莫测的现实世界，人们逐渐发现这个方法不象它看上去那么简单。多重继承的困扰，父子类之间的强烈的耦合都造成了巨大的麻烦。
<br>
我们经常发现，或者父类提供了很多东西，可我根本不需要。或者我想要某个东西，可是父类偏偏没有设想到这个可能，没有提供，而父类自作聪明预先设计好的某个设施，不但没用，反而给子类造成麻烦。
<br>

<br>
于是，四人帮们振臂高呼：不要以为OO就是随意设计你自己的类。你要遵守一定的模式！
<br>

<br>
于是，二十几片树叶被精心编织成一块遮羞布遮在OO的私处上，我们真的知道了“善恶”。一个完善的OO道德体系被圣人们建立了起来。
<br>

<br>

<br>
第二个阶段：
<br>
模式真的解放了我们吗？还是我们更糊涂了？曾几何时，我们开始痛恨singleton，鄙视template method，害怕visitor。
<br>
是时候该反思一下了。我们真的需要“继承”吗？“重载”真的很好吗？
<br>

<br>
理论界早就在研究subtype和subclass的区别，我们发现，似乎有必要区分这两个概念，subtype不见得就必须subclass，甚至，连subclass也不一定就非得subtype。
<br>

<br>
c++阵营里出现了gp的声音。大有一举将OO这个老朽打翻在地的气势。模板！到处是模板。我们用模板组合模板，代替了传统的继承，一些人甚至做出了一些相当技巧性的东西。
<br>

<br>
java跳了出来，坚定地把subtype和subclass分开。于是，我们有了interface。
<br>

<br>
所谓interface，理论上就是一个type。它和class不同，type/interface只定义方法的签名，但是不包含具体数据和实现，它只表示：给你这个类型的对象后，你能用它来做什么。它不包含：这个类型的对象具体是怎么做某一件事的。
<br>

<br>
这样，class代表实现，interface代表规范。"implements"代表subtype，"extends"是subclass同时也是subtype。
<br>
subtype和subclass被初步地分开了。我们不再仅仅有几片树叶来遮挡私出，现在我们还有了bra。
<br>

<br>
“继承”的作用被弱化，甚至被反对。要求用接口组合来代替继承的呼声日高。确实仍然有用继承和template
method比较方便的场合，但是这不再对系统的整体架构产生影响。“继承”更多地被用作一种局部的实现手段，它影响的不再是整个系统骨架，而是三两个本
身就紧密耦合的类。
<br>

<br>
interface的出现在OO内部是一个决定性的事件——如果不是一个革命的话。
<br>

<br>

<br>
它进一步完善了OO的“职责分派”体系。功能的“消费者”和“提供者”可以被明确地区分。
<br>

<br>
消费者只看见接口，而看不见类，这样，留下了一块切换不同“提供者”的空间。
<br>

<br>
OO的整体哲学甚至被上升了一个高度：我们不再执著于用树形结构，渐进式地描述世界，因为我们认识到这不大可行，世界比我们想象的要复杂得多。
<br>

<br>
OO在这个阶段被重新诠释为：<span style="font-weight: bold;">一个责任分工体系</span>。
<br>
遇到一个问题，我们通过分析需求，把它分解成互相协作的子模块。每个子模块有精确定义的职责。子模块之间通过精心设计的接口来互相通信，在保证最小耦合的基础上实现了分工合作。
<br>

<br>所谓ioc就是这样的思想的一种表达。子模块需要一个外部提供的功能时，不是直接去找到某个具体实现模块，而是通过接口把协议公开出去。这和上帝
他老人家的设计有点形似了：夏娃需要生儿子，但是虽然暂时旁边只有一个adam
gg，但是夏娃的身体构造却不是仅仅为adam设计的，上帝他老人家给夏娃的是一个跟任何男人都能生儿子的通用接口。
<br>
女人这个模块的职责被定义为：跟男人（们）生孩子。
<br>
男人这个模块的职责被定义为：跟女人（们）生孩子。
<br>

<br>

<br>
在这种思路成为系统的主导思想的时候，子模块的组装成为了一个问题。谁负责把鸡犬相闻（只看见接口），老死不相往来（看不见类）的子模块最终组合在一起呢？当只有adam夏娃的时候，上帝一努嘴，俩人就睡一起了。但是当天下呼呼嚷嚷都是男人女人的时候，这就不够效率了。
<br>
于是，月下老人就开了一个ioc容器，来负责把这些用ioc方式设计的组件们用一种最经济的方式拉到一起。
<br>

<br>

<br>

<br>
但是，有一点从OO的前驱PO那里开始到现在都没有变化，那就是，它们始终都是自顶向下的逐渐细化求精的方法论。
<br>

<br>

<br>
还有一个不太为人所关注的共同点：他们,PO, OO，都是命令式的。它们都同样以一个状态机的状态变迁为着眼点来运作系统。
<br>

<br>
回头看看还在不甘心地吵嚷不休的c++的gp，它真是一个单独的方法论吗？
<br>它难道不是也通过自顶向下的方法逐步求精？concept-model难道不就是interface-class的另一种表达形式？它难道不是也
基于状态变迁的命令式系统？（meta-programming不是，但是此处我们暂时不考虑这种生成式编程，因为它在gp里面并不算主流）
<br>
它难道不是仍然用类来封装数据，用方法来实现行为？
<br>

<br>
确实，模板因为concept不是一个强制性的类型，任何类，只要具有某个concept要求的函数签名（实际上甚至要求比这个还要松的），就可以被当作实现这个concept的一个model。如此节省了我们写adapter的工作。
<br>
另外，模板组合也比基于运行时多态，以来gc的接口组合效率高。
<br>
但是，这些细枝末节并不能qualify一个单独的方法论。
<br>

<br>
所以，我们认为，gp和programming against interface在方法论上殊途同归，在实现层面上则各有利弊。
<br>

<br>
好了，絮絮叨叨这么多，就是要给我所谈到和要进行比较的“oo”画一个圈子，不能说是“权威定义”，但是，这就是我要谈的那个“OO”。
<br>

<br>
下一节开始，我们就可以正式开始看看怎么用CO来解决我前面提出的那个例子。
<br>

<br>
与此同时，有心人也可以想想用OO（inheritance-oriented也好，interface-oriented也好）这种自顶向下的方式怎么实现这个需求繁杂，甚至有些条款还不确定的例子。
<br>

<br>
我自己是想不出太好的方法。一大堆if-else我不喜欢，父子类之间混乱的override这种乱伦行为我也有力不从心之感。</span><img src ="http://www.blogjava.net/ajoo/aggbug/27839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:29 <a href="http://www.blogjava.net/ajoo/articles/27839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子程序设计方法 之一 创世纪</title><link>http://www.blogjava.net/ajoo/articles/27838.html</link><dc:creator>ajoo</dc:creator><author>ajoo</author><pubDate>Thu, 12 Jan 2006 21:17:00 GMT</pubDate><guid>http://www.blogjava.net/ajoo/articles/27838.html</guid><wfw:comment>http://www.blogjava.net/ajoo/comments/27838.html</wfw:comment><comments>http://www.blogjava.net/ajoo/articles/27838.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ajoo/comments/commentRss/27838.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ajoo/services/trackbacks/27838.html</trackback:ping><description><![CDATA[<span class="postdetails">新开张。先炒些冷饭过来。狡兔三窟，万一哪天javaeye倒台了（robbin气的脸都青了），我辛辛苦苦码的字就丢了，就象当年在allaboutprogram的遭遇一样，哭都找不到庙门。<br>
<br>
<br>
<br>
<br>
发现老庄的连载方法很好.又能吸引眼球又能好整以暇.于是从善如流.
<br>

<br>

<br>
这几天在完善我的neptune系统和jaskell语言。顺手发现了一个logging的需求。如获至宝阿。
<br>

<br>
为什么呢？不是因为这个需求多么难，或者我的解决方法多么巧妙，而是因为，这个例子足够简单，直观，要说明它，背景知识几乎不大需要，三两句话大家就明白需要达到什么效果。这种例子可不是随便就想得到的。
<br>

<br>
而同时，它又对实现提出了一定程度的灵活性要求，正好方便我展示我叫做“面向组合子”的程序设计方法。
<br>

<br>

<br>
说到这里，不禁又有点沮丧，我也挺想象别人那样，先高举高打，玄之又玄，弄些哲学思辨，什么佛法呀，道德经阿，西游记亚，以及各位西方先哲的亟语，甚至量子力学的悖论。这样才能吸引眼球，增加人气呀。
<br>
可是，等而下之的工匠气作祟，说着说着就要拐到具体例子上去了。不争气呀。
<br>

<br>

<br>
算了，不想那么多了。论道不是俺这种俗人所擅长的，还是鼓捣“器”吧。
<br>

<br>

<br>
大致的背景是这样：
<br>
我的neptune是一个build system，在build的过程中会产生很多log信息。这些信息分为不同的重要级别。
<br>

<br>
说到这里，肯定有人已经按奈不住：用Log4j！
<br>

<br>
先不要急，我们这里不是要告诉你怎么处理你得程序中的logging需求，而是要通过这样一个容易理解的例子来说明以下“面向组合子”的编程方法。所以，这里让我们先假设我们不知道什么log4j。什么是log4j呀？
<br>

<br>
当然，大致的思路总归差不多的。因为我的neptune系统只需要一个logging的工具，而不关心这个logging工具是什么，这就是一个perfect的依赖注射的场合。
<br>

<br>
先定义接口Logger，然后从构造函数传递近来一个Logger实例，接着就直接调用Logger就是了。
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">interface</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> print<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> level, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> logException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span>;
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
print用来输出信息，但是不折行，println可以折行。
<br>
logException用来直接纪录异常。这样，对异常是直接printStackTrace，还是println(e.getMessage())就是由具体的Logger实现来决定，我的neptune只需要把遇到的异常报告给Logger就是了。
<br>

<br>

<br>
好。接下来我吭哧吭哧地把neptune完成了，剩下的就是从哪里找一个Logger实现了。
<br>

<br>
最简单的Logger实现自然就是直接往屏幕上打印了：
<br>

<br>
</span>
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%">

<tbody><tr> 	  <td><span class="genmed"><b>java代码:&nbsp;</b></span></td>
	</tr>
	<tr>
	  <td class="code"><div style="font-family: 'Courier New',Courier,monospace;">
<br>
<span style="color: rgb(153, 0, 102); font-weight: bold;">class</span> SimpleLogger <span style="color: rgb(153, 0, 102); font-weight: bold;">implements</span> Logger<span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> print<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">out</span>.<span style="color: rgb(0, 0, 0);">print</span><span style="color: rgb(0, 0, 0);">(</span>msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> println<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(153, 0, 102); font-weight: bold;">int</span> lvl, <span style="color: rgb(170, 170, 221);">String</span> msg<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; <span style="color: rgb(170, 170, 221);">System</span>.<span style="color: rgb(0, 0, 0);">out</span>.<span style="color: rgb(0, 0, 0);">println</span><span style="color: rgb(0, 0, 0);">(</span>msg<span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
&nbsp; <span style="color: rgb(153, 0, 102); font-weight: bold;">public</span> <span style="color: rgb(153, 0, 102); font-weight: bold;">void</span> printException<span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(170, 170, 221);">Throwable</span> e<span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">{</span>
<br>
&nbsp; &nbsp; e.<span style="color: rgb(0, 0, 0);">printStackTrace</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">)</span>;
<br>
&nbsp; <span style="color: rgb(0, 0, 0);">}</span>
<br>
<span style="color: rgb(0, 0, 0);">}</span>
<br>

<br>
</div>
<br>
</td>
	</tr>
</tbody>
</table>

<span class="postbody">
<br>

<br>
直接把这个SimpleLogger注射进我的neptune，整个系统就可以工作了。
<br>
no big deal，对么？
<br>

<br>

<br>
好了，下面我们开始真正实现完整的logging系统了。经过分析，我们大致有以下的需要：
<br>

<br>
<ul>1。logger可以把信息打印到log文件中。
<br><br>
2。不同的重要程度的信息也许可以打印到不同的文件中？象websphere，有error.log, info.log等。
<br>
如果这样，那么什么重要程度的信息进入error.log，什么进入warning.log，什么进入info.log也需要决定。
<br><br>
3。也许可以象ant一样把所有的信息都打印到一个文件中。
<br><br>
4。每条logging信息是否要同时打印当前的系统时间？也是一个需要抉择的问题。
<br><br>
5。不仅仅是log文件，我们还希望能够在标准错误输出上直接看见错误，普通的信息可以打印到log文件中，对错误信息，我们希望log文件和标准输出上都有。
<br><br>
6。标准输出上的东西只要通知我们出错了就行，大概不需要详细的stack trace，所以exception stack trace可以打印到文件中，而屏幕上有个简短的exception的message就够了。
<br><br>
7。warning似乎也应该输出到屏幕上。
<br><br>
8。不管文件里面是否要打印当前系统时间，屏幕上应该可以选择不要打印时间。
<br><br>
9。客户应该可以通过命令行来决定log文件的名字。
<br><br>
10。客户可以通过命令行来决定log的细节程度，比如，我们只关心info一样级别的信息，至于debug, verbose的信息，对不起，不要打印。
<br><br>
11。neptune生成的是一些Command对象，这些对象运行的时候如果出现exception，这些exception会带有execution
trace，这个execution trace可以告诉我们每个调用栈上的Command对象在原始的neptune文件中的位置（行号）。
<br>
这种exception叫做NeptuneException，它有一个printExecutionTrace(PrintWriter)的方法来打印execution trace。
<br>
所以，对应NeptuneException，我们就不仅仅是printStackTrace()了，而是要在printStackTrace()之前调用printExecutionTrace()。
<br><br><br>12。neptune使用的是jaskell语言，如果jaskell脚本运行失败，一个EvaluationException会被抛出，这个
类有一个printEvaluationTrace(PrintWriter)的方法来打印evaluation
trace，这个trace用来告诉我们每个jaskell的表达式在脚本文件中的位置。
<br>
所以，对应EvaluationException，我们要在printStackTrace()之前，调用printEvaluationTrace()。
<br><br>
13。execution trace和evaluation trace应该被打印到屏幕上和log文件两个地方。
<br><br>
14。因为printExecutionTrace()和printEvaluationTrace()本身已经打印了这个异常的getMessage()，所以，对这两种异常，我们就不再象对待其它种类的异常那样在屏幕上打印getMessage()了，以免重复。
<br><br>
15。也许还有一些暂时没有想到的需求， 比如不是写入log文件，而是画个图之类的变态要求。</ul>
<br>

<br>
大致上，我目前遇到的需求也就是这些了。
<br>

<br>
好了，允许我卖个关子，下回分解的时候再说怎么用“面向组合子”和依赖注射的方法来解决这个问题吧。
<br>

<br>
在本节结束之前，我稍微提一下“面向组合子”的来历。
<br>

<br>

<br>组合子，英文叫combinator，是函数式编程里面的重要思想。如果说OO是归纳法（分析归纳需求，然后根据需求分解问题，解决问题），那么
“面向组合子”就是“演绎法”。通过定义最基本的原子操作，定义基本的组合规则，然后把这些原子以各种方法组合起来。我最近一段时间做的东西，
jaskell不用说了，函数式语言。yan, neptune, jparsec全是用面向组合子的思想开发的。
<br>

<br>
OO就像是猜谜，给你一个苹果，然后问你：这个苹果是怎么得到的呢？然后你分析一番，说：我认为这个苹果是由分子组成的，这些分子如此这般排列，然后分子又由原子组成，如此这般排列...
<br>

<br>
而CO（面向组合子），就等于是说：这有H, C, O三种原子，强弱两种作用力，你来看看能做点什么出来吧，然后你就像搭积木一样，把这三种原子，两种作用力搭建出这大千世界，什么毛毛虫，狗熊，周星星，不小心，一下就做出了一个苹果。
<br>

<br>
OO的关键是需求。
<br>
所谓"refactor"，不过也是强调需求，让你不要自作聪明地瞎假设需求而复杂化设计。时刻着眼于当前的需求。这样，一旦需求变更，所浪费的力气可以保证最小，而且，船小才好调头嘛。
<br>
如果需求分析的不好，一切就歇菜了，虽然因为一些比如ioc之类的设计方法能让你不至于推到重来，但是需求仍然是重中之重。
<br>

<br>

<br>
那些什么上下文没有，上来就说“怎么用OO来做一个人骑车呀？”，“是人.骑(车)呀？还是车.被骑(人)？”纯粹是没头没脑地瞎掰。
<br>

<br>
而CO的关键则是组合子和组合规则的设计。这些组合方法必须非常精巧，尽量正交。组合子的设计既要简单（越简单才越容易被组合），还要完整。
<br>
比如说，对整数这个组合子，我们有+-*等组合方法，这样只要有了0,1这两个组合子，我们就可以构造出整个整数世界。
<br>
可是，精巧的组合子设计也不是那么容易的。需要有一点点数学的感觉和严密的逻辑思维基础。
<br>

<br>

<br>
有人说，上帝是用OO设计的世界，可要我是上帝，我宁可用CO。
<br>
设计几个简单的基本粒子，几个简单的相互作用力，然后让这些东西自己组合，随意发展，不是比事必躬亲，先想透彻了自己想让世界是什么样子，然后一张一张图纸地具体设计，一个一个人地造，
<br>
“撒旦，你去干坏事，往死了整这帮贱人！”
<br>
“天使，你去干好事，打个巴掌再给他们点甜枣吃。”
<br>
“儿子，你下去混混，看丫敢不敢钉死你！”
<br>
来的容易美妙？
<br>

<br>
OO的世界观是一个决定性的机械世界观。你想让世界是什么样子就要从头一点一点朝这个方向凑。设计者是全知全能的犹太教上帝耶和华。<br>
而CO的世界观是非确定性的。我自己设计出一套组合子和组合规则，然后具体这些东西会组合出什么怪物来我肚子里也没谱。就象James
Gosling，他设计出了Java语言，但是他也没办法预测Java语言都能干些什么。这是一个希腊宙斯式的，或者中国盘古式的创世纪。世界创造出来
了。怎么演化？我死后哪管它洪水滔天。<br>
<br>
<br>
<br>
哈。终于形而上起来了，爽！</span><img src ="http://www.blogjava.net/ajoo/aggbug/27838.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:17 <a href="http://www.blogjava.net/ajoo/articles/27838.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>