ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲字幕久久,2021国产精品视频,99只有精品http://www.aygfsteel.com/ajoo/articles/27849.htmlajooajooFri, 13 Jan 2006 01:08:00 GMThttp://www.aygfsteel.com/ajoo/articles/27849.htmlhttp://www.aygfsteel.com/ajoo/comments/27849.htmlhttp://www.aygfsteel.com/ajoo/articles/27849.html#Feedback0http://www.aygfsteel.com/ajoo/comments/commentRss/27849.htmlhttp://www.aygfsteel.com/ajoo/services/trackbacks/27849.html 仍然是先用oo把轮廓划出来åQŒæˆ‘们需要徏模一个接口来围绕它进行组合ã€?

å› äØ“æœ¬æ–‡æ˜¯å…³äºŽco的论˜qŽÍ¼Œé‚£ä¹ˆ˜q™ä¸ªæŽ¥å£æ€Žæ ·åˆ†æžå‡ºæ¥çš„就暂时忽略掉了åQ?

java代码: 

interface Dependency{
  Object getArgument(int i, Class type);
  Class verifyArgument(int i, Class type);
  Object getProperty(Object key, Class type);
  Class verifyProperty(Object key, Class type);
}


˜q™ä¸ªDependency接口由每个不同的¾l„äšg调用åQŒæ¥è§£å†³ä¾èµ–。如果解析失败,则抛出异常。此处,我们暂时忽略异常˜q™ä¸ª¾l†èŠ‚ã€?

getArgument负责解析一个函数参敎ͼŒ¾l„äšg告诉Dependency对象åQŒæˆ‘需要给½W?个参敎ͼŒ¾cÕdž‹ä¸ºString的解析依赖。于是就调用
getArgument(2, String.class)�

getProperty负责解析一个用某个key来标识的属性。比如一个javabean的property�

那两个verify是只取得解析到的那个½W¦åˆè¦æ±‚的组件类型,但是òq¶ä¸å®žé™…创徏对象ã€?


然后是Component接口。这里,ä¸ÞZº†åå­—½Ž€çŸ­ï¼Œæˆ‘们不用ComponentAdapter˜q™ä¹ˆæ‰™•¿çš„名字,直接ž®±æ˜¯Component好了ã€?


java代码: 

interface Component{
  Class getType();
  Object create(Dependency dep);
  Class verify(Dependency dep);
}




getType()用来˜q”回˜q™ä¸ªComponent生成的对象的¾cÕdž‹ã€?
create用来创徏˜q™ä¸ªå¯¹è±¡ã€?
verify用来保证˜q™ä¸ªå¯¹è±¡å¯ä»¥è¢«åˆ›å»ºã€?

至于容器接口åQŒå†½Ž€å•不˜q‡äº†ã€‚我们都知道pico不过是个hash tableåQŒyan的容器也差不多,虽然多几个getComponentOfType()的方法,但是大体上就是一个hash tableã€?

java代码: 

interface Container{
  Component getComponent(Object key);
  Component getComponentOfType(Class type);
}




好了。oo完毕。下面来co�


首先åQŒæœ€½Ž€å•çš„Component是什么?什么也不干åQŒç›´æŽ¥è¿”回一个倹{€?
java代码: 


class ValueComponent implements Component{
  private final Object v;
  public Class getType(){
    return v==null?null:v.getClass();
  }
  public Object create(Dependency dep){
    return v;
  }
  public Class verify(Dependency dep){
    return getType();
  }
}



½Eå¾®éš‘Ö•ƒç‚¹çš„åQŒæ˜¯æž„造函数和工厂æ–ÒŽ³•。这两个都会调用Dependencyçš„getArgument()来取得自己需要的参数实例ã€?
实际上,javaçš„reflection api里面的Methodå’ŒConstructor˜q˜æ˜¯æœ‰å¾ˆå¤šç›¸ä¼¼ç‚¹çš„ã€?
ä¸ÞZº†æŠ½å–共性,我们定义一个新的接口,叫做Function:

java代码: 

interface Function{
  Class getReturnType();
  Class[] getParameterTypes();
  Object call(Object[] args);
}



˜q™é‡ŒåQŒæˆ‘ž®×ƒ¸å±•现把Methodå’ŒConstructor匚w…ä¸ºFunction的代码了åQŒå› ä¸ºåº”该一目了然ã€?
我们只要知道我们现在可以有三个函æ•îCñ”生Function对象åQ?

java代码: 

class Functions{
  static Function ctor(Constructor ctor);
  static Function method(Object obj, Method mtd);
  static Function static_method(Class type, Method mtd);
}


当然åQŒè¿˜æœ‰ä¸€äº›è¾…助函敎ͼŒ
比如åQ?
java代码: 

static Function ctor(Class type);




然后是FunctionComponent�
java代码: 


class FunctionComponent implements Component{
  private final Function f;
  public Class getType(){
    return f.getReturnType();
  }
  public Object create(Dependency dep){
    final Class[] types = f.getParameterTypes();
    final Object[] args = new Object[types.length];
    foreach(t:types){
      args[i] = dep.getArgument(i, t);
    }
    return f.call(args);
  }
  public Class verify(Dependency dep){
    final Class[] types = f.getParameterTypes();
    foreach(t:types){
      Class arg_type = dep.verifyArgument(i, t);
      checkTypeMatch(types[i], arg_type);
    }
    return f.getReturnType();
  }
}



然后一个基本的component应该是java beançš„setter了,对应picoçš„SetterInjectionComponentAdapteråQŒä¹Ÿå¯¹åº”springçš„beanã€?
java代码: 

class BeanComponent  implements Component{
  private final Class type;
  public Class getType(){
    return type;
  }
  public Object create(Dependency dep){
    Object r = createInstance();
    setJavaBeans(r,dep);
  }
  public Class verify(Dependency dep){
    ...
  }
}


具体的实现我省略了很多。因ä¸ÞZ¼šè°ƒç”¨java.beansçš„apiåQŒåƈ且会有一些caching优化的考虑åQŒä½†æ˜¯æ€èµ\上很清楚åQŒå°±æ˜¯å¯¹æ¯ä¸ªproperty调用getProperty()ž®±æ˜¯äº†ã€?


好,最基本的就˜q™ä¹ˆå‡ ä¸ªäº†ï¼ˆå…¶å®žåQŒbean componentòq¶ä¸æ˜¯æœ€åŸºæœ¬çš„,后面我们会看刎ͼ‰ã€?

下面看看都有些什么组合规则�

1。手工指定某个参数�
java代码: 

class WithArgument implements Component{
  private final Component parent;
  private final int pos;
  private final Component arg;
  public Class getType(){
    return parent.getType();
  }
  public Object create(Dependency dep){
    return parent.create(withArg(dep));
  }
  public Class verify(Dependency dep){
    return parent.verify(withArg(dep));
  }
  private Dependency withArg(final Dependency dep){
    return new Dependency(){
      public Object getArgument(int i, Class type){
        if(i==pos){
          checkTypeMatch(type, arg);
          return arg.create(dep);
        }
        else return dep.getArgument(i, type);
      }
    }
    ...
  }
}



好,通过decorate˜q™ä¸ªDependency对象åQŒæˆ‘们得åˆîCº†æ‰‹å·¥åˆ¶å®šæŸä¸ªå‚数的能力ã€?
˜q™é‡ŒåQŒæˆ‘们对参数仍然用ComponentåQŒè€Œä¸æ˜¯ä¸€ä¸ªç®€å•çš„Objectä½œäØ“˜q™ä¸ªå‚æ•°çš„å€û|¼Œæ˜¯å› ä¸ºå‚数本íw«ä¹Ÿå¯èƒ½éœ€è¦åˆ›å»ºï¼Œå®ƒçš„依赖关系也可能需要在Dependency对象中解析。如果参æ•îC¸éœ€è¦åˆ›å»ºï¼Œé‚£ä¹ˆåQŒä½ ž®½å¯ä»¥ç”¨ValueComponent来包装一下ã€?


2。手工指定property的倹{€‚跟上面的代码非常类ä¼û|¼Œž®±æ˜¯é‡è²äº†getProperty()å’ŒverifyProperty()ã€?
java代码: 

class WithProperty implements Component{
  private final Component parent;
  private final Object key;
  private final Component prop;
  public Class getType(){
    return parent.getType();
  }
  public Object create(Dependency dep){
    return parent.create(withProp(dep));
  }
  public Class verify(Dependency dep){
    return parent.verify(withProp(dep));
  }
  private Dependency withProp(final Dependency dep){
    return new Dependency(){
      public Object getProperty(Object k, Class type){
        if(k.equals(key)){
          checkTypeMatch(type, prop);
          return prop.create(dep);
        }
        else return dep.getProperty(k, type);
      }
    }
    ...
  }
}




3。和很多¾l„åˆå­ä¸€æ øP¼Œmap是一个相当有用的¾l„合规则。它负责把一个Component˜q”回的对象作一下额外的处理åQŒtransform成另外一个对象ã€?
java代码: 

interface Map{
  Object map(Object obj);
}


java代码: 

class MapComponent implements Component{
  private final Component c;
  private final Map map;
  public Class getType(){
    return null;
  }
  public Object create(Dependency dep){
    return map.map(c.create(dep));
  }
  public Class verify(Dependency dep){
    c.verify(dep);
    return Object.class;
  }
    ...
}



注意åQŒè¿™é‡Œï¼Œå› äؓ我们无法预先知道Map˜q™ä¸ªæŽ¥å£˜q”回的对象会是什么类型,所以,我们让getType()˜q”回null来标½Cø™¿™æ˜¯ä¸€ä¸ªåŠ¨æ€å†³å®šçš„¾l„äšg¾cÕdž‹ã€?

4。比map更一般化一点的åQŒæ˜¯bind动作。所谓bindåQŒä¹Ÿæ˜¯æ ¹æ®ä¸€ä¸ªComponent创徏的对象来军_®šæŽ¥ä¸‹æ¥è¿”回什么动作。不同的是,它用˜q™ä¸ªå¯¹è±¡æ¥äñ”生另外一个ComponentåQŒè®©˜q™ä¸ªComponent来生成一个新对象。多说无益,让我们看代码åQ?
java代码: 

interface Binder{
  Component bind(Object obj);
}


java代码: 

class BoundComponent implements Component{
  private final Component c;
  private final Binder binder;
  public Class getType(){
    return null;
  }
  public Object create(Dependency dep){
    return binder.bind(c.create(dep)).create(dep);
  }
  public Class verify(Dependency dep){
    c.verify(dep);
    return Object.class;
  }
    ...
}


˜q™ä¸ªBinder接口看似½Ž€å•,但是它的存在å¯ÒŽ•´ä¸ªco都是生死攸关的大事。可以说åQŒå¦‚果没有这个Binder, což®±åŸºæœ¬å¯ä»¥ä¸å­˜åœ¨äº†ã€?
ä¸ÞZ»€ä¹ˆè¿™ä¹ˆè¯´å‘¢ï¼Ÿå› äØ“˜q™ä¸ªbinder再加上前面的那个ValueComponent代表了一¿Uéžå¸æ€¸€èˆ¬æ€§çš„计算模型åQšmonad。有一个专门的数学分支åQšç»„论,ž®±æ˜¯ç ”ç©¶monadçš„ã€?
它虽然不是放之四‹¹ïLš†å‡†çš„计算模型åQŒæ¯”如,有比它更ä¸ÞZ¸€èˆ¬æ€§çš„Arrow模型。但是,用它几乎可以描述我们一般所遇到的大量问题ã€?

除了前面的几个基本组合子之外åQŒå‡ ä¹Žæ‰€æœ‰çš„¾l„合子,如果我们愿意åQŒéƒ½å¯ä»¥ä»Žè¿™ä¸ªbind推衍出来。比如上面的mapåQŒå¦‚果用½Ž€‹zç‚¹çš„函数式语法来表˜q°çš„话(原谅我还是忍不住用函数式åQŒjava的语法就象一砣一砣屎一样压得我喘不˜q‡æ°”来)
java代码: 

map(a, f) = bind (a, \x->value(f(x)));


˜q™ä¸ªä»£ç çš„æ„æ€æ˜¯è¯ß_¼Œä½ å¯ä»¥å¾ˆè½ÀL˜“地把一个Map对象adapt到Binder对象åQŒåªè¦åœ¨bind函数里面调用åQ?
java代码: 

return new ValueComponent(map.map(v));


ž®Þp¡Œäº†ã€?

后面的很多组合子åQŒæ¯”如对一个组件生成的对象调用某个æ–ÒŽ³•åQŒè®¾¾|®ä¸€äº›java bean setteråQŒéƒ½æ˜¯ä»Ž˜q™ä¸ªbind¾l„合子衍生出来的ã€?


好了åQŒä»Šå¤©æ—¶é—´ç´§˜q«ï¼Œåˆ°æ­¤å‘Šä¸€ŒDµè½å§ã€?/span>

ajoo 2006-01-13 09:08 发表评论
]]>
论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之十一 微步毂纹ç”?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/ajoo/articles/27846.html</guid><wfw:comment>http://www.aygfsteel.com/ajoo/comments/27846.html</wfw:comment><comments>http://www.aygfsteel.com/ajoo/articles/27846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/ajoo/comments/commentRss/27846.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/ajoo/services/trackbacks/27846.html</trackback:ping><description><![CDATA[     摘要: 最˜q‘。age0提出了一个OOè®¾è®¡çš„é—®é¢˜ã€‚å› ä¸ø™¿™ä¸ªä¾‹å­æ›´åŠ è„“˜q‘生‹z»ï¼Œæ˜¯æˆ‘们老百姓所喜闻乐见的商场折扣问题,所以我准备攚w“‰æ›´å¼ ç”¨è¿™ä¸ªä¾‹å­äº†ã€‚具体的例子è¯ïLœ‹åQ? http://forum.javaeye.com/viewtopic.php?t=17714&start=0 ½Ž€è¦çš„è¯ß_¼Œéœ€æ±‚是åQ? 引用: 有这样一家超市,寚w¡¾å®¢å®žè¡Œä¼šå‘˜åˆ¶åQ?..  <a href='http://www.aygfsteel.com/ajoo/articles/27846.html'>阅读全文</a><img src ="http://www.aygfsteel.com/ajoo/aggbug/27846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/ajoo/" target="_blank">ajoo</a> 2006-01-13 06:06 <a href="http://www.aygfsteel.com/ajoo/articles/27846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之十 ˜q˜æ˜¯é‡æž„http://www.aygfsteel.com/ajoo/articles/27845.htmlajooajooThu, 12 Jan 2006 21:57:00 GMThttp://www.aygfsteel.com/ajoo/articles/27845.htmlhttp://www.aygfsteel.com/ajoo/comments/27845.htmlhttp://www.aygfsteel.com/ajoo/articles/27845.html#Feedback0http://www.aygfsteel.com/ajoo/comments/commentRss/27845.htmlhttp://www.aygfsteel.com/ajoo/services/trackbacks/27845.html 已经有点感觉用ioc container来说明co不见得是个好ä¸ÀL„äº†ã€?
˜q™ä¸ªcontainer的例子ä‹D出来åQŒæ˜Žæ˜¾æå‡ºæ„è§çš„人比那个½Ž€å•çš„logging例子ž®‘了很多ã€?
毕竟˜qžpico是怎么回事åQŒæ€Žä¹ˆç”¨ï¼Œå¾ˆå¤šäººéƒ½˜q˜ä¸è§å¾—了了。更不提多少人对pico的用法就是一个很inçš„fancy factory。买椟还珠ã€?



不过åQŒæ—¢ç„¶å¼€å§‹äº†åQŒè®©æˆ‘还是有始有¾lˆå§ã€?


˜q™ç« ˜q˜æ˜¯è®©æˆ‘们看看coçš„refactorã€?

其实åQŒå¾ˆå¤šäh问:怎样把握co里面的基本组合子的度åQ›ä»€ä¹ˆæ ·çš„组合子½Ž—是基本åQ›æ€Žæ ·åšåˆ°æ­£äº¤åQ›å¤šž®‘的基本¾l„合子才½Ž—够用;怎么知道˜q™ä¸ª¾l„合子会被用到等½{‰ã€?


其实åQŒç­”案都来自重构ã€?

没有谁一下子ž®×ƒ½œå¯¹çš„。co比è“vooåQŒæˆ‘感觉在设计上反而更å®ÒŽ˜“避免˜q‡åº¦è®¾è®¡ã€?

ä¸ÞZ»€ä¹ˆï¼Ÿ

设计oo的时候,你要分析需求,设计各个模块的通信接口åQŒè¿™ä¸ªè¿‡½E‹ï¼ŒåŒæ ·éœ€è¦ç»éªŒï¼ŒåŒæ ·éœ€è¦æ‘¸ç´¢ï¼ŒåŒæ ·æ²¡æœ‰ä¸€ít€è€Œå°±çš„æ·å¾„ã€?

但是åQŒoo设计的时候又要避免过度,一些时候,在是否通过接口预留灉|´»æ€§ï¼Œæå–å®ÒŽ˜“变化的部分,或者是ž®½é‡½Ž€å•之é—ß_¼Œ˜q˜æ˜¯æœ‰å†²½Hçš„。你需要做一个艰隄¡š„猜测和抉择ã€?
而一旦抉择作出,以后如果发现事情˜q›å±•不如所愿,那么改动接口的代ä»ïL›¸å½“的大ã€?


而如果ä‹É用coåQŒåœ¨è®¾è®¡½Ž€å•的各个¾l„合子的时候,你会以一¿Uéžå¸¸æ¸˜q›å¼çš„æ–¹å¼æ¥å‘现åQšå“¦åQŒåŽŸæ¥çš„¾l„合子设计不够正交,有这个地方可以抽出来åQŒå¥½åQŒæŠ½å‡ºæ¥åQŒæŠŠæ³¢åŠåˆ°çš„几个¾l„合子的设计修改一下ã€?

因䨓¾l„合子都非常½Ž€å•,˜q™ä¸ªå˜åŒ–çš„æ‡L及范围一般来说相当小ã€?


好,½Iø™¯ž®‘说åQŒæˆ‘们还是看具体例子ã€?


现在åQŒæˆ‘们发玎ͼŒé™¤äº†withArgument, withPropertyåQŒæˆ‘们还希望更灵‹zÕdœ°è®„¡½®å‚æ•°åQŒæ¯”如,我们希望è¯ß_¼š
    对组件X的各个参敎ͼŒ¾cÕdž‹ä¸ºA的,选取ä»?a1"标识的组件作为参数å€û|¼Œå…¶å®ƒçš„æŒ‰ç…§ç¼ºçœæ–¹å¼ã€?
    对组件Y的各个参敎ͼŒ¾cÕdž‹ä¸ºA的,选取ä»?a2"æ ‡è¯†çš„ç»„ä»¶äØ“å‚æ•°å€û|¼Œå…¶å®ƒçš„æŒ‰ç…§ç¼ºçœæ–¹å¼ã€?/ul>


    ˜q™ä¸ªéœ€æ±‚有几个点:
      1。需要能够通过key来直接指定某个某个组ä»Óž¼Œç›¸å½“于一ä¸?ref"ã€?
      2。需要对参数配置有除了按照参æ•îC½¾|®ä¹‹å¤–的更灵‹zȝš„配置åQˆæ¯”如,按照参数¾cÕdž‹åQ‰ã€?/ul>


      对第一点,我们制作以下的组合子来对应。(看,我们是可以随着需求虽然丰富我们的基本¾l„合子的集合的)
      我们期望做一个UseKey¾l„合子,它可以从容器里面取得另外一个用某个key标识的组ä»Óž¼Œç„¶åŽæŠŠä¸€åˆ‡åŠ¨ä½œéƒ½delegate˜q‡åŽ»ã€?

      java代码: 

      class UseKey extends Component{
        private final Object key;
        public Object create(Dependency dep){
          //?????????
        }
        ....
      }




      可是åQŒä¸€å¼€å§‹å†™ä»£ç åQŒå°±å‘现åQŒè¿™ä¸ªä»£ç å†™ä¸ä¸‹åŽ»ï¼æˆ‘ä»¬éœ€è¦å¾—åˆ°è¿™ä¸ªå®¹å™¨ï¼Œæ‰èƒ½ä»Žè¿™ä¸ªå®¹å™¨é‡Œé¢å–å¾—é‚£ä¸ªè¦delegate的组件。可是这个可爱容器对象在哪里呀åQ?

      仔细分析下来åQŒå‘玎ͼŒæ²¡æœ‰åŠžæ³•ã€‚å”¯ä¸€çš„åŠžæ³•æ˜¯ä¿®æ”¹Dependency接口åQŒè®©å®ƒé™¤äº†å¸®åŠ©è§£æžå‚æ•°å’Œproperty之外åQŒå†æä¾›¾l™æˆ‘们当前容器的信息ã€?

      DependencyæŽ¥å£å˜äØ“åQ?


      java代码: 

      interface Dependency{
        Object getArgument(int i, Class type);
        Object getProperty(Object key, Class type);
        Container getContainer();
      }




      WowåQè¦æ”ÒŽŽ¥å£äº†åQå…¶å®žï¼Œ˜q™ä¸€ç‚¹ä¹Ÿä¸å¯æ€•ã€‚äØ“ä»€ä¹ˆï¼Ÿ

      co˜q˜æœ‰å¦å¤–一个优ç‚ÒŽˆ‘们一直没有提及:¾l†èŠ‚ž®è£…。这个封装不是一般OO意义上的ž®è£…åQŒè€Œæ˜¯è¯ß_¼šæŠŠè¦å®žçŽ°çš„æŽ¥å£ç»†èŠ‚å°è£…è“v来,让客户通过预定义好的组合方式来扩展åQŒè€Œä¸æ˜¯è±¡oo那样让用户实现实现这个接口来扩展ã€?

      其实åQŒå¦‚果用户ä‹É用的都是Component对象åQŒè€Œåˆ›å»ºComponent对象都是通过åQ?
      java代码: 

      Container.getInstance(Object key);


      ˜q™ç§æ–¹å¼åQŒé‚£ä¹ˆï¼ŒDependency˜q™ä¸ªæŽ¥å£å·²ç»å®žé™…上æ“Ü为我们的内部实现¾l†èŠ‚äº†ã€‚ç”¨æˆäh ¹æœ¬ä¸éœ€è¦çŸ¥é“存在这么一个接口ã€?
      实际上,当我们的¾l„合子èƒö够丰富之后,完全可以把Dependency接口隐藏在包内部åQŒå½»åº•地对用户屏蔽这个接口ã€?
      如此åQŒå®¢æˆïLš„æ‰©å±•完全通过¾l„合Component对象åQŒè€Œä¸æ˜¯å®žçްComponent接口òq¶ä¸”调用Dependency接口ã€?
      不管˜q™ä¸ªDependency接口是如何设计的åQŒå¦‚何变化,我们都可以把变化隔离在我们包内部åQŒè€Œä¸ä¼šåª„响用戗÷€?

      好吧。现在假设我们修改了Dependency接口åQŒé‚£ä¹ˆUseKey可以被写为:

      java代码: 

      class UseKey extends Component{
        private final Object key;
        public Object create(Dependency dep){
           final Component c = dep.getContainer().getComponent(key);
           if(c==null)throw new ComponentNotFoundException(...);
           return c.create(dep);
        }
        ....
      }




      然后åQŒæ›´ç‰|´»çš„参数配¾|®ã€‚对˜q™ä¸ªåQŒæˆ‘们可以借鉴bind操作åQŒåšä¸€ä¸ªå¯¹å‚æ•°çš„bindã€?


      java代码: 

      interface ParameterBinder{
        Component bind(int i, Class type);
      }



      不知道你从Binder接口和ParameterBinder接口看出点什么没有?
      1。Binder, ParameterBinder接口都是¾l™ç”¨æˆ·åŽ»å®žçŽ°çš„ã€?
      2。这两个接口都不暴露Component的细节,它们的参数和˜q”回值都不涉及Component的接口签名,客户在实现这两个接口的时候,完全不必兛_¿ƒè±¡Dependency接口˜q™ç§¾l†èŠ‚ã€?
      3。返回值都是ComponentåQŒè¿™æ øP¼Œæ‰€æœ‰çš„Component¾l„合子都可以被自ç”׃‹É用ã€?

      实际上,monad¾l„合子就是通过˜q™ç§æ–¹å¼æ¥åœ¨é«˜é˜¶é€»è¾‘的层‹Æ¡ä¸Šéšè—åº•层¾l†èŠ‚ã€?



      java代码: 

      class ParameterBoundDependency implements Dependency{
        private final Dependency dep;
        private final ParameterBinder binder;
        public Object getArgument(int i, Class type){
          return binder.bind(i, type).create(dep);
        }
        ...
      }


      java代码: 

      ParameterBoundComponent extends Component{
        private final Component c;
        private final ParameterBinder binder;
        public Object create(Dependency dep){
          return c.create(new ParameterBoundDependency(dep, binder));
        }
        ...
      }


      用ParameterBinder来做一个Dependencyçš„decoratoråQŒé—®é¢˜å¾—åˆîCº†è§£å†³ã€?


      然后我们来ä‹É用ParameterBoundComponentåQŒäؓ了书写简便,我们假设Component¾cÀLœ‰ä¸€ä¸ªå‡½æ•°å«åšbind (ParameterBinder binder)。另外Components¾cÀLœ‰ä¸€ä¸ªuseKey(Object key)函数来生成一个Component对象åQŒç”¨æ¥æŒ‡å‘容器内的另外一个组件ã€?

      于是åQŒä¸Šé¢çš„需求被实现为:

      java代码: 

      Component x = ...;
      Component x2 = x.bind(new ParameterBinder(){
        public Component bind(int i, Class type){
          if(type.equals(A.class)){
            return Components.useKey("a1");
          }
          else{
            //???? è¡?
          }
        }
      });


      ˜q™ä¸ªx2¾l„äšgåQŒå°±æ˜¯äؓ了实现“当参数¾cÕdž‹ä¸ºAåQŒä‹É用a1åQŒå¦åˆ™ä‹É用缺省方式”ã€?
      可是åQŒåœ¨è¡?处,再次遇到了障¼„ã€‚这个所谓的“缺省方式”,怎么表示åQ?
      �

      ¾lè¿‡æ€è€ƒï¼Œæˆ‘们军_®šå®žçŽ°ä¸€ä¸ªuseArgument(int i, Class type)˜q™æ ·ä¸€ä¸ªç»„合子åQŒè¿™ä¸ªç»„合子可以ä¸ÕdŠ¨åœ¨å½“å‰çš„Dependencyå¯¹è±¡ä¸­é€‰æ‹©æŸä¸ªå‚æ•°ä½œäØ“è‡ªå·±çš„å€¹{€‚è¿™æ øP¼Œä¸Šé¢çš„行1ž®±å¯ä»¥å†™ä½œï¼š
      java代码: 

      Component x = ...;
      Component x2 = x.bind(new ParameterBinder(){
        public Component bind(int i, Class type){
          if(type.equals(A.class)){
            return Components.useKey("a1");
          }
          else{
            return Components.useArgument(i, type);// è¡?
          }
        }
      });



      下面来实çŽîC¸€ä¸ªUseArgument¾c»ï¼š

      java代码: 


      class UseArgument extends Component{
        private final int i;
        private final Class type;
        public Object create(Dependency dep){
          return dep.getArgument(i, type);
        }
        .....
      }



      哈。完¾ŸŽã€‚一切仍然尽在掌握ã€?
      我们可以以几乎ä“Q何方式来customizer¾l„äšg的参数和propertyã€?

      实际上,如果我们回头看看åQŒç”šè‡›_¯ä»¥å‘玎ͼŒwithArgument(int i, Class type)完全可以用bind(ParameterBinder)来重写:
      java代码: 


      Component withArgument(Component c, final int i, final Component arg){
        return c.bind(new ParameterBinder(){
          public Component bind(int k, Class type){
            if(k==i) return arg;
            else return Components.useArgument(k, type);
          }
        });
      }



      我们很开心地看到åQŒåŽŸæ¥çš„WithArgument¾c»ï¼ŒWithProperty¾c»éƒ½å¯ä»¥æ‰«è¿›åžƒåœ¾½Ž×ƒº†ã€‚我们只需要实现更加简单的ParameterBinder接口ž®±å¯ä»¥æžå®šä¸€åˆ‡ã€‚哈ã€?


      同时åQŒå¸Œæœ›ä½ ä¹Ÿçœ‹åˆîCº†éšè—˜q™äº›å…·ä½“çš„WithArgumentåQŒValueComponent¾c»ï¼Œè€Œç”¨é™æ€å·¥åŽ‚å‡½æ•°withArgument(), value()来代替的好处åQ?
      我们可以自由地重构。当发现某个¾l„合子本íw«åƈ非最½Ž€å•,而是可以从一些更½Ž€å•çš„¾l„合子推演出来,我们只需要改动这些静态工厂函敎ͼŒè€Œä¸å¿…告诉用 æˆøP¼šå¯¹ä¸èµøP¼Œæˆ‘的设计改了åQŒä¸æƒŒ™¦WithArgument¾cÖMº†åQŒä½ èƒ½ä¸èƒ½æ”¹æ”¹ä½ çš„é‚£ŒDµnew WithArgument(...)的代码?


      co让用户只å…Ïx³¨æŽ¥å£åQŒè€Œä¸è¦ç®¡æŸä¸ªåŠŸèƒ½æ˜¯ç›´æŽ¥å®žçŽ°çš„åQŒè¿˜æ˜¯ç»„合出来的。静态工厂函数提供了对这个细节的ž®è£…ã€?


      å¦å¤–ä¸€ä¸ªä¹Ÿè®æ€¼šæ¯”较常见的需求,是用一个数¾l„来一‹Æ¡æ€§æŒ‡å®šæŸä¸ªç»„件的所有参敎ͼŒæ¯”如åQ?

      java代码: 

      c.withArguments(new Component[]{c1, c2, c3});



      ˜q™ä¸ªåŠŸèƒ½ç”¨bind非常非常好实玎ͼš

      java代码: 

      Component withArguments(final Component[] args){
        return bind(new ParameterBinder(){
          public Component bind(int i, Class type){
            return args[i];
          }
        });
      }



      当然åQŒä½ ˜q˜å¯ä»¥ä‹D一反三地提出很多其它的定制参数和property的方法ã€?


      好了。今天就到这里。在¾l“束前,我来先提å‡ÞZ¸¤ä¸ªæ–°çš„需求:
      1。希望对一些用到Logger对象的类注射Logger实例åQŒè€Œè¿™ä¸ªLogger实例需要用˜q™ä¸ªä½¿ç”¨Logger对象的类对象来创建,˜q™æ ·åQŒè¿™ä¸ªLogger对象可以静态地知道谁在使用它,而不必每‹Æ¡éƒ½æž„造一个异常来取得StackTraceã€?
      比如åQ?
      java代码: 

      new ClassX(..., Loggers.instance(ClassX.class), ...);


      怎样在容器çñ”别全局地规定这个规则呢åQŸæˆ‘们不知道哪些¾l„äšg需要注ž®„LoggeråQŒä¹Ÿä¸çŸ¥é“这些组件在哪个参数注射Logger对象ã€?

      2。怎样提供¾~ºçœå‚æ•°åQŸè¿™æ øP¼Œå¦‚果某个参数的需要可以在容器中解析,则拥˜q™ä¸ªè§£æžå‡ºæ¥çš„实例,否则åQŒä‹É用一个缺省组件ã€?

      在下一节,我们会通过˜q™ä¸¤ä¸ªä¾‹å­æ¥¾l§ç®‹è§£é‡Šco的重构过½E‹ã€?/span>

         




         




      ]]>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之七 重构http://www.aygfsteel.com/ajoo/articles/27844.htmlajooajooThu, 12 Jan 2006 21:56:00 GMThttp://www.aygfsteel.com/ajoo/articles/27844.htmlhttp://www.aygfsteel.com/ajoo/comments/27844.htmlhttp://www.aygfsteel.com/ajoo/articles/27844.html#Feedback0http://www.aygfsteel.com/ajoo/comments/commentRss/27844.htmlhttp://www.aygfsteel.com/ajoo/services/trackbacks/27844.html˜q„今åQŒå‘现典型的几种疑问是:
      1。组合子的设计要求正交,要求最基本åQŒè¿™æ˜¯ä¸æ˜¯å¤ªéš¾è¾¾åˆ°å‘¢åQ?
      2。面对一些现实中更复杂的需求,¾l„合子怎样scale up呢?

      其实åQŒè¿™ä¸¤è€…都指向一个答案:重构ã€?


      要设计一个完全正交,原子åˆîC¸å¯å†åˆ†çš„¾l„合子,也许不是æ€ÀL˜¯é‚£ä¹ˆå®ÒŽ˜“。但是,我们òq¶ä¸éœ€è¦ä¸€å¼€å§‹å°±è®¾è®¡å‡ºæ¥å®Œç¾Žçš„组合子设计ã€?

      比如åQŒæˆ‘前面的logging例子åQŒTimestampLoggerè´Ÿè´£¾l™åœ¨ä¸€è¡Œçš„开头打印当前时间ã€?
      然后readonly提出了一个新的需要:打印调用˜q™ä¸ªlogger的那个javaæ–‡äšg的类名字和行受÷€?

      分析˜q™ä¸ªéœ€æ±‚,可以发现åQŒä¸¤è€…都要求在一行的开始打åîC¸€äº›ä¸œè¥Ñ€‚似乎有些共æ€?
      ˜q™ä¸ª"在行首打åîC¸€äº›å‰¾~€"ž®±æˆäº†ä¸€ä¸ªå¯ä»¥æŠ½è±¡å‡ºæ¥çš„å…±æ€?于是重构:

      java代码: 

      interface Factory{
        String create();
      }
      class PrefixLogger implements Logger{
        private final Logger logger;
        private final Factory factory;
        private boolean freshline = true;

        private void prefix(int lvl){
          if(freshline){
            Object r = factory.create();
            if(r!=null)
              logger.print(lvl, r);
            freshline = false;
          }
        }
        public void print(int lvl, String s){
          prefix(lvl);
          logger.print(lvl, s);
        }
        public void println(int lvl, String s){
          prefix(lvl);
          logger.println(lvl, s);
          freshline = true;
        }
        public void printException(int lvl, Throwable e){
          prefix(lvl);
          logger.printException(lvl, e);
          freshline = true;
        }
      }


      ˜q™é‡ŒåQŒFactory接口用来抽象往行首打印的前¾~€ã€‚这个地方之所以不是一个StringåQŒæ˜¯å› äؓ考虑到生成这个前¾~€å¯èƒ½æ˜¯æ¯”较昂è´ëŠš„åQˆæ¯”å¦‚æ‰“å°è¡ŒåøP¼Œ˜q™éœ€è¦åˆ›å»ÞZ¸€ä¸ªäÍ时异常对象)

      另外åQŒçœŸæ­£çš„Logger接口åQŒä¼šè´Ÿè´£æ‰“印所有的原始¾cÕdž‹å’ŒObject¾cÕdž‹åQŒä¾‹å­ä¸­æˆ‘们½Ž€åŒ–了˜q™ä¸ªæŽ¥å£åQŒäؓ了演½Cºæ–¹ä¾Ñ€?


      然后åQŒå…ˆé‡æž„timestamp:

      java代码: 

      class TimestampFactory implements Factory{
        private final DateFormat fmt;
        public String create(){
          return fmt.format(new Date());
        }
      }



      ˜q™æ ·åQŒå°±æŠŠtimestamp和“行首打印”解耦了出来ã€?


      下面æ·ÕdŠ TraceBackFactoryåQŒè´Ÿè´£æ‰“印当前行åïL­‰æºä»£ç ç›¸å…³ä¿¡æ¯ã€?
      java代码: 

      interface SourceLocationFormat{
        String format(StackTraceElement frame);
      }
      class TraceBackFactory implements Factory{
        private final SourceLocationFormat fmt;
        public String create(){
          final StackTraceElement frame = getNearestUserFrame();
          if(frame!=null)
            return fmt.format(frame);
          else return null;
        }
        private StackTraceElement getNearestUserFrame(){
          final StackTraceElement[] frames = new Throwable().getStackTrace();
          foreach(frame: frames){
            if(!frame.getClassName().startsWith("org.mylogging")){
              //user frame
              return frame;
            }
          }
          return null;
        }
      }



      具体的SourceLocationFormat的实现我ž®×ƒ¸å†™äº†ã€?

      注意åQŒåˆ°çŽ°åœ¨ä¸ºæ­¢åQŒè¿™ä¸ªé‡æž„都是经典的oo的思èµ\åQŒåˆ’分责任,按照责ä“Q定义Factory, SourceLocationFormat½{‰ç­‰æŽ¥å£åQŒä¾èµ–注入等。完全没有co的媄子ã€?

      ˜q™ä¹Ÿè¯´æ˜ŽåQŒåœ¨co里面åQŒæˆ‘们不是不能采用ooåQŒå°±è±¡åœ¨oo里面åQŒæˆ‘们也可以围绕某个接口按照co来提供一整套的实çŽîC¸€æ øP¼Œž®Þp±¡åœ¨oo里面åQŒæˆ‘们也可以在函数内部用po的方法来实现某个具体功能一栗÷€?


      下面开始对factory做一些co的勾当:
      先是最½Ž€å•çš„åQ?

      java代码: 

      class ReturnFactory implements Factory{
        private final String s;
        public String create(){return s;}
      }



      然后是两个factory的串联,

      java代码: 

      class ConcatFactory implements Factory{
        private final Factory[] fs;
        public String create(){
          StringBuffer buf = new StringBuffer();
          foreach(f: fs){
            buf.append(f.create());
          }
          return buf.toString();
        }
      }





      最后,我们把这几个零äšg¾l„åˆåœ¨ä¸€èµøP¼š

      java代码: 

      Logger myprefix(Logger l){
        Factory timestamp = new TimestampFactory(some_date_format);
        Factory traceback = new TraceBackFactory(some_location_format);
        Factory both = new ConcatFactory(
          timestamp,
          new ReturnFactory(" - "),
          traceback,
          new ReturnFactory(" : ")
        );
        return new PrefixLogger(both, l);
      }



      如此åQŒåŸºæœ¬ä¸ŠåQŒåœ¨è¡Œé¦–æ·ÕdŠ ä¸œè¥¿çš„éœ€æ±‚å°±å·®ä¸å¤šäº†åQŒæˆ‘们甚至也可以在行ž®¾æ·»åŠ ä¸œè¥¿ï¼Œ˜q˜å¯ä»¥é‡ç”¨è¿™äº›factory的组合子ã€?

      另一ç‚ÒŽˆ‘惌™¯´æ˜Žçš„æ˜¯ï¼š˜q™ç§é‡æž„是相当局部的åQŒä»…仅媄响几个组合子åQŒè€Œåƈ不媄响整个组合子框架ã€?


      真正影响¾l„合子框架的åQŒæ˜¯Logger接口本èín的变化。假设,readonly提出了一个非常好的意见:printException应该也接受levelåQŒå› ä¸ºæˆ‘们应该也可以选择一个exception的重要程度ã€?


      那么åQŒå¦‚果需要做˜q™ä¸ªå˜åŒ–åQŒå¾ˆä¸å¹¸çš„æ˜¯åQŒæ‰€æœ‰çš„实现˜q™ä¸ªæŽ¥å£çš„类都要改变ã€?

      ˜q™æ˜¯ä¸æ˜¯co的一个缺陷呢åQ?


      我说不是�
      即ä‹É是ooåQŒå¦‚果你需要改动接口,所有的实现¾cÖM¹Ÿéƒ½è¦æ”¹åŠ¨ã€‚co对这¿Uæƒ…况,其实˜q˜æ˜¯åšäº†å¾ˆå¤§çš„èµA献来避免的:
      只有原子¾l„合子需要实现这个接口,而派生的¾l„合子和客户代码åQŒæ ¹æœ¬å°±ä¸ä¼šè¢«æ‡L及到ã€?
      而co相比于ooåQŒåŒæ ·é¢å¯¹ç›¸åŒå¤æ‚的需求,往往原子¾l„合子的数目˜qœè¿œž®äºŽå®žé™…上要实现的语义数åQŒå¤§é‡çš„需求要求的语义åQŒè¢«é€šè¿‡¾l„合基本¾_’子来实现。也因此会减ž®‘直接实现这个接口的¾cÈš„æ•°ç›®åQŒé™ä½Žäº†æŽ¥å£å˜åŒ–çš„æ‡L及范围ã€?


      那么åQŒè¿™ä¸ªLogger接口是怎么来的呢?

      它的形成来自两方面:

      1。需求。通过oo的手ŒDµåˆ†é…è´£ä»»ï¼Œæœ€åŽåˆ†æžå‡ºæ¥çš„一个接口。这个接口不一定是最½Ž€åŒ–çš„åQŒå› ä¸ºå®ƒå®Œå…¨æ˜¯å¤–部需求驱动的ã€?

      2。组合子自èín接口½Ž€å•性和完备性的需要。有些时候,我们发现åQŒä¸€ä¸ªç»„合子里面如果没有某个æ–ÒŽ³•åQŒæˆ–者某个方法如果没有某个参敎ͼŒä¸€äº›ç»„合就无法成立。这很可能说明我们的接口不是完备的。(比如那个print函数åQ‰ã€?
      此时åQŒå°±éœ€è¦æ”¹åŠ¨æŽ¥å£ï¼Œòq¶ä¸”修改原子¾l„合子的实现ã€?
      因䨓˜q™ä¸ªå˜åŒ–完全是基于组合需求的完备性的åQŒæ‰€ä»¥æ˜¯coæ–ÒŽ³•本èín带来的问题,而不能推诿于oo设计出来的接口ã€?
      也因为如此,基本¾l„合子个数的ž®½é‡¾_„¡®€ž®±æ˜¯ä¸€ä¸ªç›®æ ‡ã€‚能够通过基本¾l„合子组合而成的,ž®±å¯ä»¥è€ƒè™‘不要直接实现˜q™ä¸ªæŽ¥å£ã€?
      当然åQŒè¿™é‡Œé¢ä»ç„¶æœ‰ä¸ªæƒè¡¡åQ?
      通过¾l„合出来的不如直接实现的直接åQŒå¯ç†è§£æ€§ï¼Œç”šè‡³å¯è°ƒè¯•性,性能都会有所下降ã€?
      而如果选择直接实现接口åQŒé‚£ä¹ˆå°±è¦åšå¥½æŽ¥å£ä¸€æ—¦å˜åŒ–,ž®±å¤šå‡ÞZ¸€ä¸ªç±»è¦æ”¹åŠ¨è¿™ä¸ªç±»çš„å¿ƒç†å‡†å¤‡ã€?

      如何抉择åQŒæ²¡æœ‰ä¸€å®šä¹‹è§„ã€?

      而因ä¸?å’?çš„ç›®æ ‡åÆˆä¸å®Œå…¨ä¸€è‡ß_¼Œå¾ˆå¤šæ—¶å€™ï¼Œæˆ‘们˜q˜éœ€è¦åœ¨1å’?之间架一个adapter以避免两个目标的冲突ã€?

      比如è¯ß_¼Œå®žé™…使用中,我可能希望Logger接口提供不要求levelçš„println函数åQŒè®©å®ƒçš„¾~ºçœå€¼å–INFOž®±å¥½äº†ã€?

      但是åQŒè¿™å¯¹ç»„合子的实现来说却是不利的。这æ—Óž¼Œæˆ‘们也许ž®Þp¦æŠŠè¿™ä¸ªå®žçŽ°è¦æ±‚çš„Logger接口和组合子的Logger接口分离开来。(比如把组合子单独挪到一个package中)ã€?



      Logger˜q™ä¸ªä¾‹å­æ˜¯éžå¸¸ç®€å•çš„åQŒå®ƒè™½ç„¶æ¥è‡ªäºŽå®žé™…项目,但是™å¹ç›®å¯¹loggingçš„éœ€æ±‚åÆˆä¸æ˜¯å¤ªå¤šåQŒæ‰€ä»¥ä¸€äº›æœ‹å‹æå‡ÞZº†ä¸€äº›åŸºäºŽå®žé™…ä‹É用的一些问题,我只能给一个怎么做的大致轮廓åQŒæ‰‹è¾¹å´æ²¡æœ‰å¯ä»¥˜qè¡Œçš„程序ã€?


      那么åQŒä¸‹é¢ä¸€ä¸ªä¾‹å­ï¼Œæˆ‘们来看看一个我¾lè¿‡äº†å¾ˆå¤šæ€è€ƒæ¯”较完善了的ioc容器的设计。这个设计来源于yan containerã€?


      先说一下ioc容器的背景知识�

      所谓ioc容器åQŒæ˜¯ä¸€¿Uç”¨æ¥ç»„装用ioc模式åQˆæˆ–者叫依赖注射åQ‰è®¾è®¡å‡ºæ¥çš„¾cȝš„工具ã€?
      一个用ioc设计出来的类åQŒæœ¬íw«å¯¹ioc容器是一无所知的。ä‹É用它的时候,可以æ ÒŽ®å®žé™…情况选择直接newåQŒç›´æŽ¥è°ƒç”¨setter½{‰ç­‰æ¯”较直接的方法,但是åQŒå½“˜q™æ ·çš„组仉™žå¸”Ržå¸¸å¤šçš„æ—¶å€™ï¼Œç”¨ä¸€ä¸ªioc容器来统一½Ž¡ç†˜q™äº›å¯¹è±¡çš„组装就可以被考虑ã€?


      æ‹¿picoä½œäØ“ä¾‹å­åQŒå¯¹åº”这样一个类åQ?

      java代码: 

      class Boy{
        private final Girl girl;
        public Boy(Girl g){
          this.girl = g;
        }
      ...
      }



      我们自然可以new Boy(new Girl());

      没什么不好的�

      但是åQŒå¦‚果这¿Uéœ€è¦ç»„装的¾cÕd¤ªå¤šï¼Œé‚£ä¹ˆ˜q™ä¸ª¾l„装ž®±å˜æˆä¸€ä»¶ç¯äººçš„‹zÖMº†ã€?

      于是åQŒpico container提供了一个统一½Ž¡ç†¾l„徏的方法:
      java代码: 


      picocontainer container = new DefaultContainer();
      container.registerComponentImplementation(Boy.class);
      container.registerComponentImplementation(Girl.class);




      ˜q™ä¸ªä»£ç åQŒå¾ˆå¯èƒ½ä¸æ˜¯ç›´æŽ¥å†™åœ¨½E‹åºé‡Œé¢åQŒè€Œæ˜¯å…ˆè¯»å–配¾|®æ–‡ä»¶æˆ–者什么东西,然后动态地调用˜q™æ®µä»£ç ã€?

      最后,使用下面的方法来取得对象åQ?

      java代码: 

      Object obj = container.getComponentInstance(Boy.class);



      注意åQŒè¿™ä¸ªcontainer.getXXXåQŒæœ¬íw«æ˜¯˜qåioc的设计模式的åQŒå®ƒä¸ÕdŠ¨åœ°åŽ»å¯ÀL‰¾æŸä¸ª¾l„äšg了。所以,¾l„äšg本èín是忌讌™°ƒç”¨è¿™¿Uapi的。如果你在组件çñ”别的代码直接依赖ioc容器的apiåQŒé‚£ä¹ˆï¼Œæ­å–œä½ ï¼Œä½ ç»ˆäºŽæˆåŠŸåœ°åŒ–ç¥žå¥‡äØ“è…æœ½äº†ã€?Laughing


      ˜q™æ®µä»£ç åQŒå®žé™…上应该出现在系¾lŸçš„æœ€å¤–围的组装程序中ã€?

      当然åQŒè¿™æ˜¯é¢˜å¤–话ã€?


      那么åQŒæˆ‘们来评估一下pico先,

      1。让容器自动å¯ÀL‰¾½W¦åˆæŸä¸ª¾cÕdž‹çš„组ä»Óž¼Œå«åšauto-wiring。这个功能方便,但是不能scale up。一旦系¾lŸå¤æ‚è“v来,ž®×ƒ¼šé€ æˆä¸€å›¢äؕ麻,ž®¤å…¶æ˜¯æœ‰ä¸¤ä¸ª¾l„äšg都符合这个要求的时候,ž®×ƒ¼šå‡ºçŽ°äºŒä¹‰æ€§ã€‚æ‰€ä»¥ï¼Œå¿…é¡»æä¾›è®©é…¾|®è€…或者程序员昄¡¤ºæŒ‡å®šä½¿ç”¨å“ªä¸ª ¾l„äšg的能力。所谓manual-wireã€?
      当然åQŒpico实际上是提供了这个能力的åQŒå®ƒå…è®¸ä½ ä‹É用组件key或者组件类型来昄¡¤ºåœ°ç»™æŸä¸ª¾l„äšg的某个参数或者某个property指定它的那个girlã€?

      但是åQŒpico的灵‹zÀL€§å°±åˆ°è¿™é‡Œäº†åQŒå®ƒè¦æ±‚ä½ çš„˜q™ä¸ªgirl必须被直接登记在˜q™ä¸ªå®¹å™¨ä¸­ï¼Œå ç”¨ä¸€ä¸ªå®è´ëŠš„全局keyåQŒå³ä½¿è¿™ä¸ªgirlåªæ˜¯ä¸“é—¨ä¸ø™¿™ä¸ªbody临时刉™€ çš„夏娃ã€?

      在java中,遇到˜q™ç§æƒ…况åQ?

      java代码: 

      void A createA(){
        B b = new B();
        return new A(b,b);
      }



      我们只需要把bä½œäØ“ä¸€ä¸ªå±€éƒ¨å˜é‡ï¼Œæž„é€ å®ŒAåQŒbž®±æ‰”掉了。然而,pico里面˜q™ä¸æˆï¼Œb必须被登记在˜q™ä¸ªå®¹å™¨ä¸­ã€‚è¿™ž®Þq›¸å½“于你必™å»è¦æŠŠb定义成一个全局变量一栗÷€?
      pico的对应代码:

      java代码: 

      container.registerComponent("b" new CachingComponentAdapter(new ConstructorInjectionComponentAdapter(B.class)));
      container.registerComponent("a", new ConstructorInjectionComponentAdapter(A.class));



      ˜q™é‡ŒåQŒäؓ了对应上面java代码中的两个参数公用一个b的实例的要求åQŒå¿…™åÀLŠŠa登记成一个singletonã€? CachingComponentAdapterè´Ÿè´£singleton化某个组ä»Óž¼Œè€? ConstructorInjectionComponentAdapterž®±æ˜¯ä¸€ä¸ªè°ƒç”¨æž„造函数的¾l„徏匚w…å™¨ã€?


      当然åQŒè¿™æ ·åšå…¶å®ž˜q˜æ˜¯æœ‰éº»çƒ¦çš„åQŒå½“container不把a登记成singleton的时候(pico¾~ºçœéƒ½ç™»è®°æˆsingletonåQŒä½†æ˜¯ä½ å¯ä»¥æ¢ç¼ºçœä¸ç”¨singletonçš„container。)åQŒéº»çƒ¦å°±æ¥äº†ã€?

      大家可以看到åQŒä¸Šé¢çš„createA()函数如果调用两次åQŒä¼šåˆ›å¾ä¸¤ä¸ªA对象åQŒä¸¤ä¸ªB对象åQŒè€Œç”¨˜q™æ®µpico代码åQŒè°ƒç”¨ä¸¤‹Æ¡getComponentInstance("a")åQŒä¼šç”Ÿæˆä¸¤ä¸ªA对象åQŒä½†æ˜¯å´åªæœ‰ä¸€ä¸ªB对象åQå› ä¸ºb被被˜q«ç™»è®îCØ“singleton了ã€?





      2。pico除了支持constructor injectionåQŒä¹Ÿæ”¯æŒsetter injection甚至factory method injection。(å¯ÒŽœ€åŽä¸€ç‚ÒŽˆ‘有点含糊åQŒä¸˜q‡å°±å‡è®¾å®ƒæ”¯æŒï¼‰ã€‚所以,跟springå¯Òޝ”åQŒé™¤äº†æ²¡æœ‰ä¸€ä¸ªé…¾|®æ–‡ä»Óž¼Œlife-cycle不太优雅ä¹? 外,什么都有了ã€?

      但是åQŒè¿™ž®±å¤Ÿäº†å—åQŸå¦‚果我们把上面的那个createA函数½Eå¾®å˜ä¸€ä¸‹ï¼š

      java代码: 

      A createA(){
        B b = new B();
        return new A(b, b.createC(x_component));
      }




      现在åQŒæˆ‘们要在b¾l„äšg上面调用createC()来生成一个C对象。完了,我们要的既不是构造函敎ͼŒä¹Ÿä¸æ˜¯å·¥åŽ‚æ–¹æ³•ï¼Œè€Œæ˜¯åœ¨æŸä¸ªäÍ时组件的基础上调用一个函数ã€?

      ¾~ºçœæä¾›çš„几个ComponentAdapter˜q™æ—¶ž®×ƒ¸å¤Ÿç”¨äº†ï¼Œæˆ‘们被告知要自己实现ComponentAdapterã€?

      实际上,pico对很多灵‹zÀL€§çš„要求的回½{”都是:自己实现ComponentAdapterã€?


      ˜q™æ˜¯å¯è¡Œçš„。没什么是ComponentAdapteròq²ä¸äº†çš„åQŒå¦‚果不计工作量的话ã€?

      一个麻烦是åQšæˆ‘ä»¬è¦ç›´æŽ¥è°ƒç”¨picoçš„api来自å·Þp§£æžä¾èµ–了。我们要自己知道是调用container.getComponentInstance("x_component")˜q˜æ˜¯container.getComponentInstance(X.class)ã€?
      ½W¬äºŒä¸ªéº»çƒ¦æ˜¯åQšé™ä½Žäº†ä»£ç é‡ç”¨ã€‚自己实现ComponentAdapterž®±å¾—自己老老实实地写,如果自己的component adapter也要动态设¾|®java bean setter的话åQŒç”­æƒ³ç›´æŽ¥ç”¨SetterInjectionComponentAdapteråQŒå¥½å¥½çœ‹java beançš„api吧ã€?


      其实åQŒæˆ‘们可以看出,pico的各¿UComponentAdapter正是正宗的decorator pattern。什么CachingComponentAdapteråQŒä»€ä¹ˆSynchronizedComponentAdapteråQŒéƒ½æ˜¯decoratorã€?

      但是åQŒè¿™ä¹Ÿå°±æ˜¯decorator而已了。因为没有围¾l•组合子的思èµ\开展设计,˜q™äº›decorator昑־—非常随意åQŒæ²¡æœ‰ä»€ä¹ˆç« æ³•,没办法支撑è“v整个的ComponentAdapter的架构ã€?

      下一章,我们会介¾lyan container对上面提出的问题以及很多其他问题的解å†Ïx–¹æ³•ã€?

      yan container的口åäh˜¯åQšåªè¦ä½ ç›´æŽ¥¾l„装能够做到的,容器ž®Þpƒ½åšåˆ°ã€?
      不管你是不是用构造函敎ͼŒé™æ€æ–¹æ³•,java beanåQŒæž„造函数然后再调用某个æ–ÒŽ³•åQŒç­‰½{‰ç­‰½{‰ã€?
      而且yan container的目标是åQŒä½ å‡ ä¹Žä¸ç”¨è‡ªå·±å®žçްcomponent adapteråQŒæ‰€æœ‰çš„需求,都通过¾l„合各种已经存在的组合子来完成ã€?


      å¯ÒŽˆ‘们前面那个很不厚道地用来刁难pico的例子,yan的解å†Ïx–¹æ³•是åQ?


      java代码: 

      b_component = Components.ctor(B.class).singleton();
      a_component = Components.ctor(A.class)
        .withArgument(0, b_component)
        .withArgument(1, b_component.method("createC"));



      b_component不需要登记在容器中,它作为局部component存在�
      是不是非常declarative呢?


      下一节,你会发现åQŒç”¨é¢å‘¾l„合子的æ–ÒŽ³•åQŒioc容器˜q™ç§ä¸œè¥¿çœŸçš„不难。我们不需要仔¾l†åˆ†æžå„¿Uéœ€æ±‚,¾_‘Ö¿ƒåˆ†é…è´£ä“Q。让我们再次体验一下吊儉KƒŽå½“不知不觉间ž®±å¤©ä¸‹å¤§æ²Èš„感觉吧ã€?

      待箋�/span>

      ]]>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之六 oraclehttp://www.aygfsteel.com/ajoo/articles/27843.htmlajooajooThu, 12 Jan 2006 21:54:00 GMThttp://www.aygfsteel.com/ajoo/articles/27843.htmlhttp://www.aygfsteel.com/ajoo/comments/27843.htmlhttp://www.aygfsteel.com/ajoo/articles/27843.html#Feedback0http://www.aygfsteel.com/ajoo/comments/commentRss/27843.htmlhttp://www.aygfsteel.com/ajoo/services/trackbacks/27843.html不少朋友说我的阐˜q°å¾ˆè‹ç™½æ— åŠ›ã€‚è¿™è®©æˆ‘å¾ˆè‹¦æ¹{€‚我¼‹®å®žæ˜¯æ‹šäº†å‘½åœ°æƒ³æŠŠé—®é¢˜è¯´æ¸…楚åQŒæˆ‘也有实际non-trivial的项目经验,怎么ž®Þp¯´ä¸æ˜Žç™½å‘¢åQŸå“ŽåQ?

      所以,˜q˜æ˜¯ä¸èƒ½ä¸å¤š¾|—嗦一下,希望能够再阐˜q°å¾—明白一炏V€?


      其实åQŒæ‰€è°“coåQŒæœ‰å¿ƒçš„æœ‹å‹ä¹Ÿè®¸èƒ½å¤Ÿæ„Ÿè§‰åˆŽÍ¼Œå®ƒå¾ˆè±¡æ˜¯è®¾è®¡ä¸€é—¨è¯­­a€ã€?
      它有™åºåº/分支åQŒæœ‰å‡½æ•°è°ƒç”¨åQŒå¼‚常处理,基本上一个程序设计语­a€æœ‰çš„东西它都有了。这些顺åº?åˆ†æ”¯ä½œäØ“è¯­è¨€çš„åŸº¼‹€è®¾æ–½åQŒè€Œä¸€äº›åº”对具体需求的原子操作åQŒï¼ˆæ¯”如WriterLoggeråQŒæ¯”如NeptuneExceptionLoggeråQ‰åˆ™å¯ä»¥çœ‹ä½œæ˜¯è¯­­a€çš„æ‰©å±•或者库ã€?

      只不˜q‡ï¼Œc/c++/java是有¾~–译器来把源代码转化成目标代码。而co的组合子则是利用了宿主语­a€åQˆæ¯”如javaåQ‰æœ¬íw«çš„能力来实现各个组合子的语义。可以说åQŒco是在设计一门语­a€ä¸­çš„语言ã€?


      最˜q‘è¿™ŒD‰|—¶é—ß_¼Œ‹¹è¡Œ˜q‡ä¸€é˜µLOPåQˆlanguage oriented programmingåQ‰ï¼Œž®±æ˜¯ç”¨domain-specific-language来处理一些特定的domain需求ã€?
      ä¸ÞZ»€ä¹ˆä¼šæœ‰è¿™¿Uè¯´æ³•å‘¢åQŸè¿˜æ˜¯å› ä¸ºdomain的需求多变灵‹z»ï¼Œä¸å®¹æ˜“琢¼‚¨ï¼Œæ‰€ä»¥äh们发现用一个灵‹zȝš„语言比用一些功能相å¯ÒŽ­»æ¿çš„库更å®ÒŽ˜“对付ã€?
      但是dsl的实çŽîC¸æ˜¯é‚£ä¹ˆå®¹æ˜“的。而co是不是可以说¾l™æˆ‘们提供了一个相对廉ä»ïLš„创徏自己的domain specific language的途径å‘?
      我们虽然不能�
      java代码: 

      if level > 1 then logger1 else logger2


      臛_°‘可以退而求其次åQŒå†™å‡?
      java代码: 

      ignore(1, logger1, logger2);







      当然åQŒè¿™¿Uå­è¯­è¨€ç›¸æ¯”于宿主语­a€åQŒç¼ºä¹è°ƒè¯•器的帮助,¾~ÞZ¹¾~–译器的优化åQŒç¼ºä¹å„¿Uide的支持,可用性程度是大大不如的ã€?

      但是åQŒå®ƒä¹Ÿæœ‰å®ƒçš„好处åQŒé‚£ž®±æ˜¯åQŒä¸ç”¨é¢å¤–进行一‹Æ¡ç¼–译;写出来的东西和宿主语­a€æ— ç¼é›†æˆåQ›å¯ä»¥è‡ªåŠ¨åˆ©ç”¨å®¿ä¸»è¯­­a€é‡Œé¢çš„一切设施。等½{‰ã€?

      那么如果把coä½œäØ“ä¸€ä¸ªè¯­­a€æ¥è€ƒè™‘åQŒæ˜¯ä¸æ˜¯ä¼šç»™æˆ‘们一些别的启½Cºå‘¢åQ?

      oz曄¡»è´¨ç–‘åQŒæ‰€è°“çš„coåQŒæ€Žæ ·å†›_®šåŸºæœ¬çš„组合子åQŸæ€Žä¹ˆæ äh‰çŸ¥é“¾l„合子够用了åQ?

      那么åQŒè®¾è®¡è¯­­a€çš„æ—¶å€™ï¼Œæ€Žä¹ˆè®¾è®¡åŸºæœ¬çš„语­a€è®¾æ–½åQŸæ€Žä¹ˆæ ïLŸ¥é“这个设施是不èƒöåQŒè¿˜æ˜¯å¤ªå¤šå‘¢åQ?
      ˜q™æ˜¯ä¸ªå¤§è¯é¢˜åQŒè¯­­a€è®¾è®¡éžå¸¸æœ‰äº‰è®®æ€§å’Œä¸»è§‚性。但是,也仍然是有些共性的。比如,几乎所有的语言都支持顺序,if/elseåQŒé€’å½’/循环åQŒå‡½æ•°å®šä¹‰ç­‰ã€‚相当多我们熟悉的语­a€˜q˜æ”¯æŒå¼‚常处理,字符ä¸ÔŒ¼Œæ•´æ•°½{‰ã€?

      我们éšùN“不能从这里借鉴一些东西?如果我们把基本的nop, ™åºåºåQŒåˆ†æ”¯ä½œä¸ºå¯åЍco的基本要求,˜q™ç®—不算是一个可以遵循的guidline呢?

      另外åQŒä¸åŒçš„语言åQŒæ ¹æ®å®ƒæ‰€é¢å‘的领域,˜q˜æœ‰ä¸€äº›ä¸åŒçš„内徏操作åQŒæ¯”如perlåQŒé¢å‘文本处理,所以内å»ÞZº†regexpåQŒè€Œc/c++å› äØ“ç›´æŽ¥é¢å¯¹æœºå™¨¼‹¬äšg模型åQŒæ‰€ä»¥æä¾›äº†æŒ‡é’ˆã€?
      那么åQŒæ ¹æ®æˆ‘们的¾l„合子所要面对的应用¾cÕdž‹åQŒæˆ‘们也可以预先定义一些内建的原始¾l„合子,比如那个WriterLoggerã€?


      一般来è¯ß_¼Œå¯¹general purpose的语­a€åQŒè®¾è®¡çš„基础设施都是非常”基¼‹€â€œçš„åQŒåŸº¼‹€åˆ°å‡ ä¹Žä¸ä¼šæœ‰ä»€ä¹ˆè®¾æ–½æ˜¯å¤šä½™çš„。同æ—Óž¼Œä¹ŸåŸº¼‹€åˆîC¸€èˆ¬äh都可以没有什么困隑֜°æŽŒæ¡åŸºæœ¬çš„语法语义ã€?
      那么˜q™äº›è¯­è¨€ç”¨è¿™ä¹ˆæœ‰é™çš„聊聊几个设施怎么对应它不可能预见的各¿UçŽ°å®žä¸­çš„éœ€æ±‚å‘¢åQ?

      我们òqÏx—¶å¯¹å¯ä»¥ç”¨½Ž€å•çš„if-elseåQŒé¡ºåºï¼Œå¾ªçޝž®±å¯ä»¥åšå‡ ä¹Žä»ÖM½•我们能想到的事情感到惊讶了吗åQŸå¯¹æŸä¸ªè¯­è¨€èƒ½å¦å¤„理复杂的需求担忧了吗?

      ä¸ÞZ»€ä¹ˆæ²¡æœ‰å‘¢åQŸå°±åœ¨äºŽâ€ç»„合“的威力。就是那么几个简单的设施åQŒç»„合è“v来却可以å…ähœ‰å·¨å¤§çš„力量ã€?

      同样åQŒåœ¨è®¾è®¡¾l„合子的时候,如果我们遵åó@˜q™äº›å…±æ€§ï¼ŒåŒæ—¶åœ¨å’Œå…·ä½“需求磨合的时候积极改˜q›ç»„合子本èínåQŒåº”该就可以辑ֈ°ä¸€ä¸ªå¯ä»¥æ»¡æ„çš„¾l„合子系¾lŸã€?


      说到˜q™é‡ŒåQŒå¯èƒ½æœ‰äººé—®åQšä½ ä¸æ˜¯è¯´ç»„合子¾pȝ»Ÿæ˜¯è„±¼›»éœ€æ±‚自己发展的吗?


      ˜q™ä¸ªåQŒæ€Žä¹ˆè¯´å‘¢åQŸè¿˜æ˜¯è¯´è¯­è¨€ã€‚设计一个语­a€åQŒåŽŸåˆ™ä¸Šæ˜¯è®¾è®¡ä¸€äº›å’Œå…·ä½“éœ€æ±‚æ²¡æœ‰è€¦åˆçš„åŸº¼‹€è®¾æ–½åQŒç„¶åŽè®©å†™å…·ä½“应用的人组合这些基¼‹€è®¾æ–½è¾‘Öˆ°æˆ‘们语言设计者不可能都预见到的某些具体效果ã€?
      但是åQŒåœ¨è¯­è¨€è®¾è®¡å’Œé€æ¸å‘展˜q‡ç¨‹ä¸­ï¼Œä»ç„¶ä¼šä»Žç”¨æˆ·åQˆå°±æ˜¯ç¨‹åºå‘˜åQ‰é‚£é‡Œå¾—到反馈,什么样的需求是他们需要的åQŒä»€ä¹ˆæ ·çš„设施不好用åQŒç„¶åŽè®¾è®¡è€…再˜q›è¡Œæ”¹è¿›ã€?

      一个语­a€åQŒä¸€èˆ¬ä¸ä¼šæ˜¯æŸä¸ªå…·ä½“需求通过划分责ä“QåQŒè‡ª™å¶å‘下的设计åQŒæœ€åŽä½œä¸ø™¿™ä¸ªéœ€æ±‚的附属模块被开发出来。更多的情况åQŒæ˜¯è¯­è¨€çš„设计者对可能面对的需求有 一个大致了解,òq¶ä¸”知道˜q™ç§å¯èƒ½çš„需求是变化的,不确定的åQŒäºŽæ˜¯æ‰ä¼šä»ŽåŸºæœ¬è®¾æ–½å¼€å§‹è®¾è®¡è¿™ä¸ªè¯­­a€åQŒæœ€åŽäº¤ä»˜ç»™å¼€å‘具体应用的人来使用ã€?


      ¾l„合子系¾lŸä¹Ÿéµåó@一æ ïLš„规律。组合子的设计需要来自具体需求的灉|„Ÿå’Œçº æ­£ã€‚但是,基本¾l„合子本íw«å´ä¸èƒ½è€¦åˆäºŽè¿™äº›å…·ä½“需求ã€?
      ¾l„合子的设计者应该对可能面对的需求有大致的了解,但是òq¶ä¸éœ€è¦å®Œæ•´åœ°é¢„测˜q™ç§å¤šå˜çš„需求ã€?


      当然åQŒç»„合子˜q™ç§è¯­è¨€ä¸­çš„语言åQŒè¿˜æœ‰ä¸å®ÒŽ˜“理解的弱炏V€‚当¾l„合层次增多åQŒé€»è¾‘变得复杂åQŒè¿™ä¸ªå¤æ‚çš„¾l„合子可不象写在一般的½E‹åºè®¾è®¡è¯­è¨€é‡Œé¢çš„代码那æ ïL®€æ˜Žï¼Œjava¾Jççš„语法让˜q™ç§è¯­è¨€ä¸­çš„语言对一些程序员也许ž®Þp±¡æ˜¯ç¥žåº™é‡Œé¢çš„¼œžè°•一样难以理解,甚至让äh望而生畏ã€?

      ˜q™ä¸€åŠæ˜¯å› äØ“java本èín没有提供对这¿Ué«˜é˜‰™€»è¾‘的直接支持,¾l„合的语法相对繁琐。如果用haskellåQŒä‹É用语­a€æä¾›çš„do-notationåQŒåŞ式上的复杂程度就没了ã€?

      另一斚w¢åQŒé«˜é˜‰™€»è¾‘都是有这¿Uå¼±ç‚¹çš„ã€?
      其实åQŒå°±½Ž—是ooåQŒç›¸æ¯”于poåQŒå®ƒçš„多态也是降低可理解性的ã€?

      å› æ­¤åQŒå°±è±¡æˆ‘们也不能在oo中到处override虚函æ•îC¸€æ øP¼Œ¾l„合子的使用也要有一定的度,˜q‡çŠ¹ä¸åŠã€?



      好了åQŒæ²¡æœ‰å®žé™…ä¾‹å­çš„è®ø™¿°å·²ç»å¤ªé•¿äº†ã€‚肯定已¾læœ‰äººæ˜æ˜æ¬²ç¡äº†ã€?


      做个调查åQŒæˆ‘下面的例子有几个选择åQ?

        1。简单的predicate。就是一个具有bool is(Object v);æ–ÒŽ³•的接口ã€?
        2。ant的FileSelector。一个predicate的变体�
        3。swing提到的jdbc的action。负责数据库操作的组合子�
        4。yan containerçš„component。负责从ä»ÀL„çš„æž„造函敎ͼŒå·¥åŽ‚æ–ÒŽ³•åQŒjava bean以及它们的ä“Q意组合来产生和注ž®„组件。比pico/spring灉|´»å¾ˆå¤šã€?
        5。neptuneçš„commandåQŒè´Ÿè´£è°ƒç”¨ä“Q何ant task以及其它的可能返回一个java对象的函数。是一个一般化了的ant taskã€?/ul>


        ˜q™äº›ä¸œè¥¿éƒ½æ˜¯åŸÞZºŽ¾l„合子的。大家觉得对哪一个更有兴­‘£å‘¢åQŸæˆ‘有些拿不定主意哪个更合适ã€?/span>

        ]]>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之五 新约http://www.aygfsteel.com/ajoo/articles/27842.htmlajooajooThu, 12 Jan 2006 21:52:00 GMThttp://www.aygfsteel.com/ajoo/articles/27842.htmlhttp://www.aygfsteel.com/ajoo/comments/27842.htmlhttp://www.aygfsteel.com/ajoo/articles/27842.html#Feedback0http://www.aygfsteel.com/ajoo/comments/commentRss/27842.htmlhttp://www.aygfsteel.com/ajoo/services/trackbacks/27842.html每个ž®å­©åˆšå¼€å§‹èµ°è·¯çš„æ—¶å€™éƒ½æ˜¯è·Œè·Œæ’žæ’žçš„ã€?
        我们不自量力åQŒå¦„图踩着上帝的步伐前˜q›ã€‚结果就是这么几个简单的象白开水似的类。失望吗åQŸæ˜¯ä¸æ˜¯é€ ç‰©è¯•图模仿造物ä¸ÀLœ¬íw«å°±æ˜¯ä¸€¿Uå¯½W‘的狂妄呢?

        别急,让我们失声痛哭之前先看看我们˜q™å‡ æ­¥èµ°çš„æ˜¯ä¸æ˜¯ä¸€é’׃¸å€¹{€?

          1。logger可以把信息打印到logæ–‡äšg中ã€?/span>

          å®ÒŽ˜“åQŒç›´æŽ¥åˆ›å»ÞZ¸€ä¸ªWriterLoggerž®±å¥½äº†ã€?

          2。不同的重要½E‹åº¦çš„信息也许可以打印到不同的文件中åQŸè±¡websphereåQŒæœ‰error.log, info.log½{‰ã€?
          如果˜q™æ ·åQŒé‚£ä¹ˆä»€ä¹ˆé‡è¦ç¨‹åº¦çš„信息˜q›å…¥error.logåQŒä»€ä¹ˆè¿›å…¥warning.logåQŒä»€ä¹ˆè¿›å…¥info.log也需要决定ã€?/span>

          不同的文件吗åQŸå¥½åŠžå•Šã€‚å°±æ˜¯ä¸åŒçš„PrintWriter对象了ã€?
          java代码: 

          Logger err_log = writer(err_writer);
          Logger warning_log = writer(warning_writer);
          Logger info_log = writer(info_writer);



          各个文äšg记录不同重要½E‹åº¦çš„信息是么?
          java代码: 

          err_log = filter(ERROR, err_log, nop());
          warning_log = filter(WARNING, warning_log, nop());
          info_log = filter(INFO, info_log, nop());


          最¾lˆæŠŠä¸‰ä¸ªä¸åŒçš„logger串联èµäh¥ž®±æ˜¯äº†ï¼š
          java代码: 

          Logger logger = sequence(err_log, warning_log, info_log);




          3。也许可以象ant一æ ähŠŠæ‰€æœ‰çš„ä¿¡æ¯éƒ½æ‰“å°åˆ°ä¸€ä¸ªæ–‡ä»¶ä¸­ã€?/span>

          ˜q™å°±æ›´ç®€å•了åQŒå°±ä¸€ä¸ªæ˜¯WriterLoggerã€?


          4。每条logging信息是否要同时打印当前的¾pȝ»Ÿæ—‰™—´åQŸä¹Ÿæ˜¯ä¸€ä¸ªéœ€è¦æŠ‰æ‹©çš„问题ã€?/span>

          拿不定主意是么?没关¾p»ï¼Œæƒ›_¥½äº†å†å‘Šè¯‰æˆ‘ã€?
          反正åQŒå¦‚果你需要系¾lŸæ—¶é—ß_¼Œæˆ‘只需è¦?
          java代码: 


          logger = timestamp(logger);






          5。不仅仅是logæ–‡äšgåQŒæˆ‘们还希望能够在标准错误输å‡ÞZ¸Šç›´æŽ¥çœ‹è§é”™è¯¯åQŒæ™®é€šçš„信息可以打印到logæ–‡äšg中,寚w”™è¯¯ä¿¡æ¯ï¼Œæˆ‘们希望logæ–‡äšg和标准输å‡ÞZ¸Šéƒ½æœ‰ã€?/span>

          可以创徏针对标准输出的LoggeråQŒç„¶åŽå’Œæ‰“印log æ–‡äšgçš„logger串联èµäh¥ã€?
          java代码: 


          Logger std_logger = writer(new PrintWriter(System.err));
          std_logger = ignore(ERROR, std_logger);
          logger = sequence(std_logger, logger);






          6。标准输å‡ÞZ¸Šçš„东西只要通知我们出错了就行,大概不需要详¾l†çš„stack traceåQŒæ‰€ä»¥exception stack trace可以打印到文件中åQŒè€Œå±òq•上有个½Ž€çŸ­çš„exceptionçš„messagež®±å¤Ÿäº†ã€?/span>

          ˜q™é‡Œéœ€è¦å¯¹std_logger½Eå¾®æ”¹å†™ä¸€ä¸‹ï¼š
          java代码: 

          PrintWriter out = new PrintWriter(System.err);
          std_logger = new ErrorMessageLogger(out, writer(out));
          std_logger = ignore(ERROR, std_logger, nop());


          用ErrorMessageLogger来改写对异常的log逻辑�



          7。warningä¼ég¹Žä¹Ÿåº”该输出到屏幕上ã€?/span>

          好啊。就是把ignore函数里面的ERROR换成WARNINGž®±å¥½äº?
          java代码: 

          std_logger = ignore(WARNING, std_logger, nop());




          8。不½Ž¡æ–‡ä»‰™‡Œé¢æ˜¯å¦è¦æ‰“印当前¾pȝ»Ÿæ—‰™—´åQŒå±òq•上应该可以选择不要打印旉™—´ã€?/span>

          对std_logger不掉用timestampž®±æ˜¯äº†ã€?

          9。客户应该可以通过命ä×o行来军_®šlogæ–‡äšg的名字ã€?/span>

          ˜q™æ¡å’Œlogger¾l„合子其实没什么关¾p…R€?

          10。客户可以通过命ä×o行来军_®šlog的细节程度,比如åQŒæˆ‘们只兛_¿ƒinfo一æ ïLñ”别的信息åQŒè‡³äºŽdebug, verboseçš„ä¿¡æ¯ï¼Œå¯¹ä¸èµøP¼Œä¸è¦æ‰“印ã€?/span>

          生成那个最¾lˆä‹É用的Logger对象的时候,再ignore一下就行了åQ?

          java代码: 

          logger = ignore(some_level, logger, nop());




          11。neptune生成的是一些Command对象åQŒè¿™äº›å¯¹è±¡è¿è¡Œçš„æ—¶å€™å¦‚果出现exceptionåQŒè¿™äº›exception会带有execution traceåQŒè¿™ä¸ªexecution trace可以告诉我们每个调用栈上的Command对象在原始的neptuneæ–‡äšg中的位置åQˆè¡ŒåøP¼‰ã€?
          ˜q™ç§exception叫做NeptuneExceptionåQŒå®ƒæœ‰ä¸€ä¸ªprintExecutionTrace(PrintWriter)的方法来打印execution traceã€?
          所以,对应NeptuneExceptionåQŒæˆ‘们就不仅仅是printStackTrace()了,而是要在printStackTrace()之前调用printExecutionTrace()ã€?/span>

          NeptuneExceptionLoggerž®±æ˜¯¾l™è¿™ä¸ªå‡†å¤‡çš„å‘€ã€?

          12。neptune使用的是jaskell语言åQŒå¦‚æžœjaskell脚本˜qè¡Œå¤ÞpÓ|åQŒä¸€ä¸ªEvaluationException会被抛出åQŒè¿™ä¸? ¾cÀLœ‰ä¸€ä¸ªprintEvaluationTrace(PrintWriter)的方法来打印evaluation traceåQŒè¿™ä¸ªtrace用来告诉我们每个jaskell的表辑ּåœ¨è„šæœ¬æ–‡ä»¶ä¸­çš„ä½¾|®ã€?
          所以,对应EvaluationExceptionåQŒæˆ‘们要在printStackTrace()之前åQŒè°ƒç”¨printEvaluationTrace()ã€?/span>

          JaskellExceptionLogger


          13。execution traceå’Œevaluation trace应该被打印到屏幕上和logæ–‡äšg两个地方ã€?/span>

          ˜q™å°±æ˜¯è¯´åQŒä¸Šé¢ä¸¤ä¸ªLogger应该被应用到std_loggerå’Œlogger两个对象中ã€?


          14。因为printExecutionTrace()å’ŒprintEvaluationTrace()本èín已经打印了这个异常的getMessage()åQŒæ‰€ä»¥ï¼Œå¯¹è¿™ä¸¤ç§å¼‚常åQŒæˆ‘们就不再象对待其它种¾cȝš„异常那样在屏òq•上打印getMessage()了,以免重复ã€?


          ž®±æ˜¯è¯ß_¼Œä¸€æ—¦ä¸€ä¸ªexception被发现是NeptuneExceptionåQŒé‚£ä¹ˆErrorMessageLoggerž®Þp¦è¢«èŸ©˜q‡äº†ã€?
          java代码: 

              final Logger err_logger = new ErrorMessageLogger(writer);
              final Logger jaskell_logger = new JaskellExceptionLogger(writer, err_logger);
              final Logger neptune_logger = new NeptuneExceptionLogger(writer, jaskell_logger);
              return neptune_logger;


          ˜q™ä¸ªneptune_logger先判断异常是不是NeptuneExceptionåQŒå¦‚果是åQŒç›´æŽ¥å¤„理,否则åQŒä¼ é€’ç»™ jaskell_logger。jaskell_logger¾l§ç®‹åˆ¤æ–­åQŒå¦‚果不是它感兴­‘£çš„åQŒå†ä¼ é€’ç»™ErrorMessageLogger来做最后的¾~? 省处理ã€?


          15。也许还有一些暂时没有想到的需求, 比如不是写入logæ–‡äšgåQŒè€Œæ˜¯ç”ÖM¸ªå›¾ä¹‹¾cȝš„变态要æ±?/span>ã€?

          æ”ùN©¬˜q‡æ¥å§ã€‚看我们的组合子能不能对付ã€?


        很惊讶地发现åQŒå°±˜q™ä¹ˆå‡ ä¸ªž®å„¿¿U‘似的积木,ž®×ƒ¼¼ä¹Žå…¨éƒ¨è§£å†³äº†æ›¾è®©æˆ‘们烦恼的这些需求?

        ä¸ÞZº†¾l™å¤§å®¶ä¸€ä¸ªå®Œæ•´çš„印象åQŒä¸‹é¢æ˜¯æˆ‘实际项目中使用˜q™äº›¾l„合子应对上面这些需求的代码åQ?
        java代码: 

        public class StreamLogger {
          private final OutputStream out;
         
          /**
           * To create a StreamLogger object.
           * @param out the OutputStream object that the log message should go to.
           */

          public StreamLogger(OutputStream out) {
            this.out = out;
          }
         
          /**
           * To get the OutputStream that the log messages should go to.
           */

          public OutputStream getStream() {
            return out;
          }
          private static Logger getBaseLogger(PrintWriter writer){
            final Logger nop = new NopLogger();
            final Logger base = Loggers.logger(writer);
            final Logger neptune_logger = new NeptuneExceptionLogger(writer, nop);
            final Logger jaskell_logger = new JaskellExceptionLogger(writer, nop);
            return Loggers.sequence(
                new Logger[]{neptune_logger, jaskell_logger, base}
            );
          }
          private static Logger getEchoLogger(PrintWriter writer){
            return new ErrorMessageLogger(writer);
          }
          private static Logger getErrorLogger(PrintWriter writer){
            final Logger err_logger = new ErrorMessageLogger(writer);
            final Logger jaskell_logger = new JaskellExceptionLogger(writer, err_logger);
            final Logger neptune_logger = new NeptuneExceptionLogger(writer, jaskell_logger);
            return neptune_logger;
          }
          /**
           * Get the Logger instance.
           * @param min_level the minimal critical level for a log message to show up in the log.
           * @return the Logger instance.
           */

          public Logger getDefaultLogger(int min_level){
            final PrintWriter writer = new PrintWriter(out, true);
            final PrintWriter err = new PrintWriter(System.err, true);
            final PrintWriter warn = new PrintWriter(System.out, true);
            final Logger all = Loggers.sequence(new Logger[]{
                Loggers.ignore(getErrorLogger(err), Logger.ERROR),
                Loggers.filter(getEchoLogger(warn), Logger.WARNING),
                getBaseLogger(writer)
              }
            );
            return Loggers.ignore(all, min_level);
          }
        }



        ä¸ÞZº†åäh‡’åQŒæˆ‘没有用配¾|®æ–‡ä»Óž¼Œž®±æ˜¯æŠŠè¿™äº›ç­–略硬¾~–码˜q›java了。好在上面的代码非常declarativeåQŒæ”¹èµäh¥ä¹Ÿå¾ˆå®ÒŽ˜“ã€?

        没习惯读代码的朋友。这里奉劝还是读一è¯Õd§ã€‚很多时候,代码才是说明问题的最好手ŒDüc€‚æˆ‘ç›æ€¿¡åQŒåªæœ‰è¯»äº†ä»£ç ï¼Œä½ æ‰èƒ½çœŸæ­£å°åˆ°CO的味道ã€?


        有朋友问åQŒä½ ˜q™ä¸ªä¸œè¥¿å’Œdecorator pattern有什么区别呀åQŸä¹çœ‹ä¸ŠåŽ»ï¼Œ˜q˜çœŸæ˜¯é•¿å¾—差不多呢。不都是往现有的某个对象上面附加一些功能吗åQ?
        也许是把。我不知道象SequenceLogger˜q™ç§æŽ¥å—一个数¾l„çš„åQŒæ˜¯å¦ä¹Ÿå«åšå¯ÒŽ•°¾l„çš„decoratoråQ›ä¹Ÿä¸çŸ¥é“IgnoreLogger接受了两个Logger对象åQŒè¿™ä¸ªdecorator½I¶ç«Ÿæ˜¯ä¿®é¥°è°çš„å‘¢åQ?

        其实åQŒå«ä»€ä¹ˆåå­—无所谓。我˜q™é‡Œè¦è®²çš„,是一¿Uä»ŽåŸºæœ¬¾_’子推演¾l„合的思èµ\。åŞ式上它也许碰巧象decorator, 象ioc。但是正如workinghard所è¯ß_¼ˆ˜q™å¥è¯æ·±å¾—我心)åQŒæ€èµ\的切入点不同ã€?

        如果你仔¾l†çœ‹ä¸Šé¢çš„代码,也许你会有所感觉åQšå¯¹Logger的千奇百怪的¾l„合本èín已经有点象一个程序代码了ã€?
        如果用伪码表½Cºï¼š

        java代码: 

          all_logger = ignore messages below ERROR for getErrorLogger(err);
                  filter messages except WARNING for getEchoLogger(warn);
                  baseBaseLogger(writer);
          ignore messages below lvl for all_logger;


        当组合子­‘Šæ¥­‘Šå¤šåQŒéœ€æ±‚越来越复杂åQŒè¿™ä¸ªç»„合就会越来越象个½E‹åºã€?

        ˜q™é‡ŒåQŒå®žé™…上åQŒï¼ˆè‡›_°‘我希望如此)åQŒæˆ‘们的思维已经从打åîC»€ä¹ˆä»€ä¹ˆä¸œè¥¿ä¸Šå‡äؓ在Logger˜q™ä¸ª¾U§åˆ«çš„组装了ã€?

        ˜q™ä¹Ÿž®±æ˜¯æ‰€è°“higher order logic的意思ã€?


        所谓combinator-orientedåQŒåœ¨˜q™é‡ŒåQŒå°±ä½“现为系¾lŸæ€§åœ°åœ¨é«˜é˜‰™€»è¾‘的层面上考虑问题åQŒè€Œä¸æ˜¯å¦‚decorator那样的零敲碎打的几个功能模块ã€?
        大量的需求逻辑被以声明式的方式在高阉™€»è¾‘中实玎ͼŒè€ŒåŸºæœ¬çš„¾l„合子只负责实现原字操作ã€?


        当然åQŒç¼ºç‚¹ä¹Ÿæ˜¯æ˜Žæ˜„¡š„åQŒå¯¹æ­¤æˆ‘不讳­a€åQ?

          高阶逻辑不容易调试,当我们ä‹É用一个组合了十几层的复杂的Logger对象的时候(真正用了co˜q™ç§æƒ…况不少见)åQŒä¸€æ—¦å‡ºçްbugåQŒè·Ÿítªçš„æ—¶å€™æˆ‘们就会发现象是陷入了一个迷宫,从一个组合子跟踪˜q›å…¥å¦ä¸€ä¸ªç»„合子åQŒç»•来绕厅R€?

          另外åQŒå¼‚常的stack trace也无法反映组合层‹Æ¡å…³¾p»ï¼Œé€ æˆé”™è¯¯å®šä½éºÈƒ¦ã€?/ul>


          ˜q™ä¹Ÿè®æ€¸æ˜¯co本èínçš„é—®é¢˜ï¼Œè€Œæ˜¯å› äØ“java˜q™ç§oo语言对co没有提供语言上的支持。但是无论如何,˜q™å¯¹åœ¨java中大规模使用co造成了障¼„ã€?

          也许你还无法理解。åã^时我们在java中用那么几个decoratoråQŒæœ¬íw«éžå¸¸ç®€å•,所以debug, trace都不是问题。可是,一旦orientedèµäh¥åQŒæƒ…况就不同了。街上有两辆车和成千上万辆èžRåQŒå¯¹äº¤é€šé€ æˆçš„压力截然不同ã€?


          ˜q˜æœ‰æœ‹å‹åQŒå¯¹co如何把握有疑问。难道což®±æ˜¯çžŽçŒ«¼„°æ­»è€—子么?

          其实åQŒæ— è®ºco˜q˜æ˜¯ooåQŒå¯¹è®¾è®¡è€…都是有一定要求的ã€?
          oo要求你了解需求,òq¶ä¸”¾léªŒä¸°å¯ŒåQŒä¹Ÿè¦æœ‰ä¸€ç‚¹ç‚¹˜qæ°”ã€?
          co也要求经验,˜q™ä¸ª¾léªŒæ˜¯è®¾è®¡ç»„合子¾pȝ»Ÿçš„经验。什么样的组合子是好的?怎么才算是èƒö够简单?什么组合规则是合理的?½{‰ç­‰åQŒè¿™äº›ï¼Œä¹Ÿæœ‰è§„律可åó@åQŒå°±åƒoo的各¿Uæ¨¡å¼ä¸€æ —÷€‚同æ—Óž¼Œä¹Ÿå¯ä»¥refactor。毕竟,怎么½Ž€å•地想问题比怎么分解复杂问题可能˜q˜æ˜¯è¦å®¹æ˜“掌握一炏V€?

          不过åQŒco对经验的要求½Eå¾®ž®ä¸€ç‚¹ï¼Œä½†æ˜¯å¯ÒŽ•°å­¦å’Œé€»è¾‘的基本功要求则多了一炏V€‚有了一些数学和逻辑斚w¢çš„基本功åQŒé‚£ä¹ˆè®¾è®¡ç»„合子ž®×ƒ¼šè½ÀL¾çš„多ã€?

          co也要有一点点˜qæ°”。所以遇åˆîC½ æ€Žä¹ˆæƒ³ä¹Ÿæƒ³ä¸æ˜Žç™½çš„æƒ…况,ž®±åˆ«æ­ÀLŠ—å•¦ï¼Œä¹Ÿè®¸˜q™ä¸ªé—®é¢˜ž®±æŠ½è±¡ä¸å‡ºç»„合子来,或者以我们普通äh的智慧抽象不出来ã€?



          co是银弹吗åQŸå½“然不是,臛_°‘以我的功力没有这¿Uè‡ªä¿¡ã€?
          遇到复杂的问题我也是先分解需求,面向接口的。只有问题的规模被控制在了一定的范围åQŒæˆ‘才会试图用co来解决问题。靠着对co的一些经验和感觉åQŒä¸€æ—¦å‘çŽîCº†å¯ä»¥¾l„合子化的概念,成果会非常显著ã€?


          而且åQŒcoå’Œooå…Ïx³¨çš„层面也不同。co是针对一个单独的概念åQˆè¿™ç‚¹å€’有点象aoåQ‰ï¼Œä¸€ç‚¹ä¸€ç‚ÒŽ¼”¾lŽï¼Œæž„成一个可以ä“Q意复杂的¾pȝ»ŸåQŒä¸€ä¸ªå¥½çš„coä¹? 会大大减ž®‘需要引入的概念数。而oo是处理大量互相或者有联系åQŒæˆ–者没有联¾pÈš„æ¦‚念åQŒç ”½I¶æ€Žä¹ˆæ ähŠŠä¸€ä¸ªçœ‹ä¸ŠåŽ»å¤æ‚çš„ç³»¾lŸçš„å¤æ‚åº¦æŽ§åˆ¶ä½ã€‚æ‰€ä»¥ä¸¤è€…åÆˆä¸æ˜¯äº? 相排斥的。自™å¶å‘下,自底向上åQŒä¹Ÿè®¸è¿˜æ˜¯ä¸¤æ‰‹ä¸€èµähŠ“æ›´å¥½äº›ã€?

          ˜q™æ®µæ—‰™—´åº”用co做了几个软äšg后,感觉co最擅长的领域是åQ?
          问题域有比较ž®‘的概念åQŒæ¦‚å¿ëŠ®€æ˜Žæ¸…晎ͼˆæ¯”如logger, predicate, factoryåQŒcommandåQ‰ï¼Œä½†æ˜¯å¯Òަ‚å¿ëŠš„实现要求非常灉|´»çš„场合ã€?
          ˜q™ç§æ—¶å€™ï¼Œç”¨oož®±æœ‰æ— å¤„下嘴之感。毕竟概念已¾låˆ†è§£äº†åQŒèŒè´£ä¹Ÿæ¸…楚åQŒå°±æ˜¯æ€Žä¹ˆæä¾›ä¸€ä¸ªå¯ä»¥çµ‹z»é€‚应变化的体¾p»ï¼Œè€Œå¯¹˜q™ä¸ªåQŒooòq¶æ²¡æœ‰æä¾›ä¸€ä¸ªæ–¹æ³•论。基本上ž®±æ˜¯ç”¨po的方法吭哧吭哧硬做。而co此时ž®±å¯ä»¥å¤§å±•用武之地。å×I补这个空隙ã€?



          看过圣经的,也许有感觉,旧约里面的上帝严厉,¾lå…¸åQŒå°±åƒæ˜¯ä¸€ä¸ªçº¯¾_¹çš„fp语言åQŒæ¯ä¸ªç¨‹åºå‘˜éƒ½è¢«˜q«æŒ‰ç…§å‡½æ•°å¼åQŒç»„合子的方式思考问题,你感觉困难?那是你不够虔诚。你们äh不合我的心意åQŒæˆ‘æ·ÒŽ­»ä½ ä»¬åQ?


          而新¾U¦é‡Œé¢ï¼Œæ˜Žæ˜¾æ·ÕdŠ äº†å¾ˆå¤šäh情味å„ѝ€‚上帝通过自己的儿子和äºÞZ»¬å’Œè§£äº†ã€‚既然æïˆæ­ÖM¸€æ³¢ï¼Œå†æ¥ä¸€æ³¢è¿˜æ˜¯è¿™æ øP¼Œé‚£ä¹ˆæ˜¯ä¸æ˜¯è¯´å¤§å®¶åº”该各让一步呢åQ?
          coå’ŒooåQŒæ—¢ç„¶å„自都不能宣称自己ž®±æ˜¯é“¶å¼¹åQŒé‚£ä¹ˆäؓ什么不能拉èµäh‰‹æ¥å‘¢åQŸæˆ‘们不是神åQŒä¸å¯èƒ½çœŸæ­£æŒ‰ç…§¼œžçš„æ–¹å¼ç”¨åŸºæœ¬ç²’子组合演化世界,所以就åˆ? 象清教徒一栯‚‹¦è‹¦è¿½æ±‚不可能的目标了。但是,上帝的组合之道毕竟相当åéy妙,在有些时候荆‹‚˜é‡Œé¢å‡ºçŽ°ç«ç„°çš„æ—¶å€™ï¼Œæˆ‘ä»¬åˆä½•å¿…å›ºæ‰§åœ°æ‹’ç»é€ ç‰©ä¸Èš„好意呢?½CÆD²Œ 地说一壎ͼšâ€œè°¢äº†ï¼è€å¤§â€ã€‚不是皆大欢喜?


          ˜q™ä¸€èŠ‚æˆ‘ä»¬ç‘ô¾l­è®²è§£äº†˜q™ä¸ªlogging的例子。实际上åQŒlogging是一个非常简单的¾l„合子,下面如果大家对这个例子有疑问åQŒæˆ‘会尽力解½{”ã€?

          然后åQŒæˆ‘们会˜q›å†›ä¸‹ä¸€ä¸ªä¾‹å­ã€?/span>

          ]]>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之四 燃烧的荆‹‚?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/ajoo/articles/27841.html</guid><wfw:comment>http://www.aygfsteel.com/ajoo/comments/27841.html</wfw:comment><comments>http://www.aygfsteel.com/ajoo/articles/27841.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/ajoo/comments/commentRss/27841.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/ajoo/services/trackbacks/27841.html</trackback:ping><description><![CDATA[<span id="wmqeeuq" class="postdetails">唧唧歪歪一大堆。肯定早有äh不耐烦了ã€? <br> "你丫˜q˜æœ‰æ²¡æœ‰ç‚¹å®žåœ¨çš„东西呀åQ? <br> 要是我,可能也早ž®±å¿ä¸ä½äº†ã€? <br> <br> 好,好。我其实òq¶æ²¡æœ‰å¿˜è®°å‰é¢è¯´çš„那个logging的例子。卖了这么长旉™—´çš„关子,除了有想形而上的虚荣心外,也是想给大家多一ç‚ÒŽ—¶é—´æ¥åšég¸€ä¸‹è¿™ä¸ªä¾‹å­ï¼Œè®©ç†Ÿæ‚‰OO的朋友肚子里面多ž®‘有个腹½Eѝ€? <br> <br> 下面åQŒæˆ‘来ç‘ô¾l­ä¸Šå›žä¹¦è¯´åˆ°çš„这个loggingã€? <br> <br> 前面列ä‹D了那么一大堆ä¹×ƒ¸ƒå…«ç³Ÿçš„需求,不知道是不是有äh和我一æ ïLœ‹ç€˜q™äº›¾Jæ‚的条目闹心。我在做的时候其实只想了五六条需求,ž®±å·²¾lå¼€å§‹çƒ¦äº†ã€‚何况还有一 些暂时不知道如何抉择的几个疑问点。最初Kiss出来的那个logger实现明显不能用了。refactorçš„ä­hå€ég¹Ÿæœ‰é™ã€? <br> <br> 怎么办?智慧果也许给了我们智慧,但是˜q™æ™ºæ…§æ¯•竟是有限的。侧头看去,蓦然看见荆棘里蟩动的火焰åQŒé‚£æ˜¯ä¸Šå¸çš„光芒么? <br> <br> 好,既然˜q™æ¡è·¯çœ‹æ¥æ¯”è¾ƒåŽåøP¼Œæ¢æ¡è·¯è¯•试看也未ž®ä¸å¯ã€‚èµ°˜q™æ¡è·¯çš„好处在于åQŒæˆ‘们可以暂时不用理会这些讨厌的“需求”了。CO˜q™ä¸ªæ–ÒŽ³•è®ÞZ¸æ˜¯ä»¥éœ€æ±‚äØ“ä¸­å¿ƒåQŒè€Œæ˜¯ä»Žåº•层的¾l„合子出发,ž®±åƒž®å­©å­æ‘†å¼„积木,我们只管发挥自己的想象力åQŒçœ‹çœ‹æˆ‘们能摆弄å‡ÞZº›ä»€ä¹ˆä¸œè¥¿æ¥ž®±å¥½äº†ã€? <br> <br> <br> 如果一切顺利,我们希望能够跨越瀚æ“v高山åQŒèµ°åˆ°æµç€å¥¶å’Œèœœçš„åœŸåœ°ã€‚æ‰€æœ‰è¿™äº›äØ•ä¸ƒå…«¾pŸçš„需求,我们希望他们能够被简单地配置åQŒæˆ–者至ž®‘能够通过声明式的æ–ÒŽ³•来“声明”,而不是通过˜q‡ç¨‹å¼çš„æ–ÒŽ³•来“实现”ã€? <br> <br> 出发之前åQŒé¼“舞以下士气先ã€? <br> 前面charonè¯ß_¼Œ˜q™ç§ä¸œè¥¿¾cÖM¼¼å…¬ç†¾pȝ»Ÿã€‚确实,非常非常¾cÖM¼¼ã€‚不˜q‡ï¼Œé—¨æ§›òq¶ä¸åƒè¿™ä¸ªåå­—å¬æ¥é‚£ä¹ˆå“äººçš„é«˜ã€‚æˆ‘ä»¬åÆˆä¸éœ€è¦ä¸€ä¸‹å­ž®±å®Œå…¨æŠŠå®Œå¤‡æ€§è€ƒè™‘清楚åQŒæˆ‘们不是上帝,没有˜q™ä¹ˆå¤§æœ¬äº‹ã€? <br> <br> ¾cÖM¼¼äºŽxp + refactoringåQŒæˆ‘们的¾l„合子的建造也一样可以摸着矛_¤´˜q‡æ²³åQŒèµ°ä¸€æ­¥çœ‹ä¸€æ­¥çš„ã€? <br> <br> 比如åQŒå‡å¦‚我的Logger接口定义的时候没有print函数而只有printlnåQŒé‚£ä¹ˆåŽé¢æˆ‘们会发现在制造打印当前时间的¾l„合子的时候会出现éºÈƒ¦ã€‚不˜q‡ï¼Œæ²¡å…³¾p»ï¼Œ½{‰åˆ°æ„è¯†åˆ°æˆ‘们需要一个print()函数的时候,回过头来refactor也是可以的ã€? <br> <br> <br> ä¸ÞZº†è¯´æ˜Ž˜q™ç‚¹åQŒæˆ‘们现在假设LoggeræŽ¥å£æ˜¯è¿™æ øP¼š <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   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>   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 id="wmqeeuq" class="postbody"> <br> <br> 好,路æ˜O漫而修˜qœå…®åQŒæˆ‘们就˜q™æ ·æŒ‰ç…§ä¸Šå¸çš„æ˜­½CÞZ¸Šè·¯å§åQŒè™½ç„¶å‰è·¯äº‘ž®é›¾é”ã€? <br> <br> <br> <br> 首先åQŒä“Q何组合子¾pȝ»Ÿçš„徏立,都è“v步于最最基本最最½Ž€å•çš„¾l„合子。然后再一步步¾l„合ã€? <br> <br> 比如åQŒå¸ƒž®”代数必然è“v步于trueå’ŒfalseåQ›è‡ªç„¶æ•°èµäh­¥äº?åQ?åQŒç„¶åŽå°±å¯ä»¥æŽ¨æ¼”出整个系¾lŸã€? <br> <br> 那么åQŒå¯¹Logger来说åQŒæœ‰0å’?吗? <br> <br> 有的ã€? <br> <br> 0ž®±æ˜¯ä¸€ä¸ªä»€ä¹ˆéƒ½ä¸åšçš„Loggerã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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 id="wmqeeuq" class="postbody"> <br> <br> åQˆæ³¨åQŒä¸è¦å°çœ‹è¿™ä¸ªä»€ä¹ˆéƒ½ä¸åšçš„LoggeråQŒå®ƒçš„作用大着呢。你能想象一个没æœ?的整数系¾lŸå—åQŸï¼‰ <br> <br> 什么是1呢?一个直接向文äšg中打åîC¿¡æ¯çš„应该ž®±æ˜¯ä¸€ä¸?了ã€? <br> 伪码如下åQ? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>     write msg to log file. <br>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     write exceptioon to log file. <br>   <span style="color: rgb(0, 0, 0);">}</span> <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> 那么åQŒæ€Žä¹ˆå®žçް˜q™ä¸ª¾cÕd‘¢åQ? <br> <br> ˜q™é‡ŒåQŒæˆ‘们遇åˆîC¸€ä¸ªä¸œè¥¿è¦æŠ‰æ‹©åQŒæ–‡ä»¶æ‰“开是要关闭的。那么谁负责打开文äšgåQŸè°è´Ÿè´£å…³é—­åQŸæ˜¯å¦è¦åœ¨æž„造函æ•îC¸­new FileOutputStream()åQŸï¼Œç„¶åŽå†æä¾›ä¸€ä¸ªclose()函数来close˜q™ä¸ªstreamåQ? <br> <br> ½{”案是:不要ã€? <br> <br> 无论是ioc也好åQŒè¿˜æ˜¯CO的组合方法也好,一个原则就是要ž®½é‡ä¿æŒäº‹æƒ…½Ž€å•。那么,什么最½Ž€å•?我们此处真正需要的是什么?一个file么? <br> 不,其实一个PrintWriterž®Þpƒö够了ã€? <br> 当然åQŒæœ€¾lˆæ–‡ä»¶å¿…™å»è¿˜æ˜¯è¦é€šè¿‡ä»£ç æ‰“å¼€åQŒå…³é—­ã€‚但是,既然反正也要打开文äšgåQŒæˆ‘们这里不åŽÈ®¡ä¹Ÿä¸ä¼šå¢žåŠ ä»€ä¹ˆå·¥ä½œé‡åQŒå¯¹ä¹ˆï¼Ÿé‚£ä¹ˆä¸ÞZ»€ä¹ˆä¸ä¹å¾—清闲呢? <br> “先天下之忧而忧”这¿Uæ€æƒ³æ˜¯æœ€æœ€è¦ä¸å¾—çš„ã€? <br> <br> <br> 于是åQŒæœ€½Ž€å•çš„1åº”è¯¥æ˜¯è¿™æ øP¼š <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>     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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   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>      this.<span style="color: rgb(0, 0, 0);">writer</span> = writer; <br>   <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 id="wmqeeuq" class="postbody"> <br> <br> “哈åQè¿˜è¯´ä»€ä¹ˆCO。你˜q™ä¸æ˜¯å‰½½Hƒioc pattern吗?â€? <br> 完了åQŒè¢«æŠ“个现åŞ。还真是ioc pattern。其实,世界上本来没有什么新东西åQŒæ‰€è°““方法论”,本来是一¿Uæ€è€ƒæ–¹æ³•,而不是说形式上必然和别äh不同。不˜q‡ï¼Œè¯´æˆ‘剽窃åQŒæˆ‘ž®±å‰½½Hƒå§ã€? <br> <br> <br> 好。最½Ž€å•的原子写出来了。希望到现在åQŒä½ ˜q˜æ˜¯ä¼šè§‰å¾—:“介åQŒä»‹æœ‰ä»€ä¹ˆå‘€åQŸâ€? <br> <br> <br> 下面来看¾l„合规则。都可以弄些什么组合规则呢åQŸè®©æˆ‘来掰着脚指头数一数ã€? <br> 有一点作为thumb of rule需要注意的åQšæ¯ä¸ªç»„åˆè§„åˆ™å°½é‡ç®€å•ï¼Œòq¶ä¸”<span style="font-weight: bold;">只做一件事</span>ã€? <br> <br> 1。顺序。把若干个logger对象™åºåºå†™ä¸€éï¼Œè‡ªç„¶æ˜¯ä¸€¿Uç»„合方式ã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>     <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>       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>     <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;">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>     <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>       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>     <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;">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>   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>     this.<span style="color: rgb(0, 0, 0);">loggers</span> = ls; <br>   <span style="color: rgb(0, 0, 0);">}</span> <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> <br> <br> 2。逻辑分支。当消息的重要程度等于某一个çñ”别的时候,写logger1åQŒå¦åˆ™å†™logger2ã€? <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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>   <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>     <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> ä¸ÞZº†½Ž€‹zï¼Œä¸‹é¢çš„例子我ž®×ƒ¸å†™æž„造函æ•îCº†ã€? <br> <br> <br> 3。忽略。当消息的重要程度大于等于某一个值的时候,我们写入logger1åQŒå¦åˆ™å†™å…¥logger2ã€? <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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>   <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>     <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> <br> 其实åQ?å’?本来可以¾lŸä¸€æˆä¸€ä¸ªç»„合规则的åQŒéƒ½æ˜¯æ ¹æ®æ¶ˆæ¯é‡è¦ç¨‹åº¦æ¥åˆ¤æ–­logger走向的。如果我用的是一个函数式语言åQŒæˆ‘会毫不犹豫地用一个predicate函数来做˜q™ä¸ªæŠ½è±¡ã€? <br> 可惜åQŒjava中如果我要这么做åQŒå°±è¦å¼•入一个额外的interfaceåQŒè¿˜è¦å¤šåšä¸¤ä¸ªadapter来处理ignoreå’ŒfilteråQŒå°±ä¸ÞZº†èŠ‚çœä¸€ä¸ªç±»å’Œå‡ è¡Œä»£ç ï¼Œ˜q™æ ·åšæ„Ÿè§‰ä¸æ˜¯å¾ˆå€¼å¾—åQŒæ‰€ä»¥å°±keep it stupid了ã€? <br> <br> <br> <br> 对了。我说“CO不看需求”了么?如果说了åQŒå¯¹ä¸è“våQŒæˆ‘撒谎了ã€? <br> CO¼‹®å®žä¸æ˜¯ä¸€ä¸ªä»¥éœ€æ±‚äØ“ä¸­å¿ƒçš„æ–¹æ³•è®ºã€‚å®ƒæœ‰è‡ªå·Þqš„¾l„合¾pȝ»Ÿè¦å…³å¿ƒã€? <br> 但是需求也仍然在CO中有反映。我们前面提出的那些需求比如打印系¾lŸæ—¶é—´ä»€ä¹ˆçš„不会被无中生有地实现ã€? <br> 只不˜q‡ï¼Œåœ¨CO里面åQŒè¿™äº›éœ€æ±‚不再媄响系¾lŸæž¶æž„,而是被实çŽîCؓ一个一个独立的¾l„合子。同æ—Óž¼Œæˆ‘们抛开需求之间复杂的逻辑关系åQŒä¸Šæ¥ç›´å¥”主题而去ž®±å¥½äº†ã€? <br> <br> 4。对exception直接打印getMessage()ã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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>      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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>      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>   <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 id="wmqeeuq" class="postbody"> <br> <br> 5。对了,该处理NeptuneException了。如果一个exception是NeptuneExceptionåQŒæ‰“印execution traceã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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>     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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>       <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>     <span style="color: rgb(0, 0, 0);">}</span> <br>     <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span> <br>       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>     <span style="color: rgb(0, 0, 0);">}</span> <br>   <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 id="wmqeeuq" class="postbody"> <br> <br> 6。对EvaluationExceptionåQŒç…§çŒ«ç”»è™Žã€? <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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>     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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>       <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>     <span style="color: rgb(0, 0, 0);">}</span> <br>     <span style="color: rgb(153, 0, 102); font-weight: bold;">else</span><span style="color: rgb(0, 0, 0);">{</span> <br>       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>     <span style="color: rgb(0, 0, 0);">}</span> <br>   <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 id="wmqeeuq" class="postbody"> <br> <br> 7。在每行消息前打印系¾lŸæ—¶é—´ã€? <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>     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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     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>     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>   <span style="color: rgb(0, 0, 0);">}</span> <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> ˜q™ä¸ª¾cÕd…¶å®žå¯ä»¥å†æ³¨å°„˜q‘来一个DateFormat来控制日期格式。但是这不是重点åQŒæˆ‘们忽略掉了它ã€? <br> 可是åQŒè¿™ä¸ªç±»æœ‰ä¸€ä¸ªå¾ˆåˆ«æ‰­çš„地方,在printException中,我们必须要把¾pȝ»Ÿæ—‰™—´å•ç‹¬æ‰“å°åœ¨ä¸€è¡Œï¼Œç„¶åŽå†æ‰“å°å¼‚å¸æ€¿¡æ¯ã€? <br> <br> ˜q™å¯ä¸æ˜¯æˆ‘们惌™¦çš„æ•ˆæžœã€‚我们本来是惌™®©¾pȝ»Ÿæ—‰™—´å‡ºçŽ°åœ¨åŒä¸€è¡Œçš„ã€? <br> 怎么办?回头看看åQŒå¦‚æžœLogger接口多一个print函数åQŒä¸€åˆ‡å°±˜qŽåˆƒè€Œè§£äº†ã€‚重构ã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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>     <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>       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>     <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;">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>     printTimestamp<span style="color: rgb(0, 0, 0);">(</span>level<span style="color: rgb(0, 0, 0);">)</span>; <br>     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>     freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">false</span>; <br>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     printTimestamp<span style="color: rgb(0, 0, 0);">(</span>level<span style="color: rgb(0, 0, 0);">)</span>; <br>     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>     freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>; <br>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     printTimestamp<span style="color: rgb(0, 0, 0);">(</span>ERROR<span style="color: rgb(0, 0, 0);">)</span>; <br>     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>     freshline = <span style="color: rgb(153, 0, 102); font-weight: bold;">true</span>; <br>   <span style="color: rgb(0, 0, 0);">}</span> <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> <br> 当然åQŒå‰é¢çš„一些组合子也都要增加这个print函数。相信这应该不难。就留给大家做个¾lƒä¹ å§ã€? <br> <br> <br> 好啦。到现在åQŒæˆ‘们手里已¾læœ‰ä¸¤ä¸ªåŸºæœ¬¾l„合子,7个组合规则。应该已¾lå¯ä»¥ç»„合出来不ž®‘有意义没意义的东西了ã€? <br> <br> ä¸ÞZº†é¿å…å†™ä¸€å¤§å †çš„new和冗长的¾cÕdå­—,我们做一个facade¾c»ï¼Œæ¥æä¾›ç®€çŸ­ç‚¹çš„名字,节省我们一些键盘损耗ã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>   <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>   ... <br> <span style="color: rgb(0, 0, 0);">}</span></div> <br> </td> </tr> </tbody> </table> <span id="wmqeeuq" class="postbody"> <br> <br> ˜q™æ ·åQŒåœ¨ç”¨è¿™äº›ç»„合子的时候大概代码能够好看一点吧ã€? <br> <br> <br> 好了åQŒèµ°äº†è¿™ä¹ˆè¿œåQŒï¼ˆè™½ç„¶å¾ˆå¤šäººå¯èƒ½è¿˜æ˜¯è§‰å¾—根本没看见什么激动äh心的东西吧?都是½Ž€å•得不能再简单的ž®ç±»åQŒæœ‰ä»€ä¹ˆäº†ä¸è“v的呢åQŸï¼‰ã€‚让我们停下脚步åQŒçœ‹çœ‹è¿™ä¹ˆä¿¡é©¬ç”±¾~°æŠŠæˆ‘们带到了哪里吧ã€? <br> <br> <br> 下一回,我们会试着用这些组合子和组合规则来看看能不能对付前面提出的那些ä¹×ƒ¸ƒå…«ç³Ÿçš„需求ã€?/span><img src ="http://www.aygfsteel.com/ajoo/aggbug/27841.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:46 <a href="http://www.aygfsteel.com/ajoo/articles/27841.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之三 å¤×ƒ¹å›?之补å…?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/ajoo/articles/27840.html</guid><wfw:comment>http://www.aygfsteel.com/ajoo/comments/27840.html</wfw:comment><comments>http://www.aygfsteel.com/ajoo/articles/27840.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/ajoo/comments/commentRss/27840.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/ajoo/services/trackbacks/27840.html</trackback:ping><description><![CDATA[<span id="wmqeeuq" class="postdetails">å¤×ƒ¹å›­å‘了之后。有的朋友对“OO是一¿Uè‡ª™å¶å‘下的æ–ÒŽ³•è®ºâ€çš„è®ø™¿°æœ‰äº›ç–‘é—®ã€? <br> <br> ˜q™é‡Œè¡¥å……一下ã€? <br> <br> 如果认可OO是一个责ä»Õdˆ†é…ä½“¾p»ï¼Œé‚£ä¹ˆè‡ªé¡¶å‘下ž®±æ˜¯ä¸€ä¸ªè‡ªç„¶çš„逻辑¾l“论ã€? <br> <br> <br> 没有分析出来“需求”,也就无所谓“责仠Z€ï¼ŒäºŽæ˜¯æ ÒŽœ¬ž®±æ— æ‰€è°““OO”了ã€? <br> <br> ˜q™ç§ä»Žåˆ†æžéœ€æ±‚,分解需求,分配责ä“QåQŒå†åˆ†æžå­éœ€æ±‚,分解子需求,在子模块内分配责ä»Èš„方式åQŒè¢«æˆ‘称为“自™å¶å‘下”ã€? <br> <br> <br> 至于说xp, tdd和自™å¶å‘下是不矛盄¡š„。它们也都是要依赖于需求分析的。test case是什ä¹?不就是需求么? <br> 当然åQŒè¿™äº›æ–¹æ³•论òq¶ä¸è¦æ±‚需求百分之癄¡š„¾l†åŒ–åQŒå®ƒä»¬è®¤å¯å˜åŒ–,拥抱变化åQŒåŠ›æ±‚å˜åŒ–æ—¶çš„ä»£ä»ähœ€ž®ã€‚不˜q‡ï¼Œä¸ç®¡æ€Žä¹ˆè¯ß_¼Œå®ƒä»¬ä»ç„¶æ˜¯è¦ç€çœégºŽå½“前的需求的åQŒåº”寚wœ€æ±‚å˜åŒ–çš„èƒ½åŠ›æ˜¯å¦å¤–ä¸€ä¸ªè¯é¢˜ï¼Œå®ƒåÆˆä¸èƒ½è¡¨ç¤º˜q™äº›æ–ÒŽ³•è®ÞZ¸æ˜¯è‡ª™å¶å‘下ã€? <br> <br> “自底向上”确实古已有之,PO时代也确实有˜q™ä¸ªææ³•。但是,它的¾~ÞZ¹æ–¹å‘性,¾~ÞZ¹é‡ç”¨èƒ½åŠ›åQŒç¼ºä¹æ•´ä½“组¾l‡ç­‰½{‰å¼Šç—…è®©å®ƒä»Žæ¥éƒ½æ²¡æœ‰æˆäØ“è®¾è®¡çš„ä¸»‹¹ï¼Œæ²¡æœ‰æˆäؓ一个主导整体或者部分设计的思想ã€? <br> 最多算是公有制体制内的¿Uæœ‰åˆ¶è¡¥å……而已。PO时代它的åœîC½ž®×ƒ¸é«˜ï¼ŒåˆîCº†OO时代åQŒå¼ºè°ƒèŒè´£åˆ†é…ï¼Œå®ƒæ›´æ˜¯å‡ ä¹Žæ“Üä¸ÞZ¸€ä¸ªåŽ†å²è¯æ±‡äº†ã€? <br> <br> <br> 也许你会è¯ß_¼Œæˆ‘在调用xcerces, stl的时候,éšùN“也是自顶向下åQŸæˆ‘可从来没有给stl的作者分配过责ä“Q啊ã€? <br> <br> ˜q™å…¶å®žå’Œè´£ä“Q分配òq¶ä¸çŸ›ç›¾ã€‚中间如果发现可以重用的模块åQŒåªè¦è¿™ä¸ªæ¨¡å—向外承诺的责ä“Q½W¦åˆæˆ‘的期望åQŒæˆ‘ž®±å¯ä»¥ç”¨ã€‚仍然是自顶向下åQŒéœ€æ±‚驱动,责ä“Q驱动ã€? <br> 而且åQŒxcerces˜q™äº›åº“设计的时候,也一栯‚¦å‡æƒ³ä¸€ä¸‹éœ€æ±‚,然后从需求出发的。(stlä¸æ˜¯å¾ˆä¸€æ øP¼Œå®ƒä¸€å®šç¨‹åº¦ä¸Šæœ‰CO的媄子,从基本组合子逐渐演绎的方法在其中也有体现åQŒæ¯”如那个iterator和所有围¾l•iterator的算法等åQ?/span><img src ="http://www.aygfsteel.com/ajoo/aggbug/27840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:43 <a href="http://www.aygfsteel.com/ajoo/articles/27840.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之二 å¤×ƒ¹å›?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/ajoo/articles/27839.html</guid><wfw:comment>http://www.aygfsteel.com/ajoo/comments/27839.html</wfw:comment><comments>http://www.aygfsteel.com/ajoo/articles/27839.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/ajoo/comments/commentRss/27839.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/ajoo/services/trackbacks/27839.html</trackback:ping><description><![CDATA[<span id="wmqeeuq" class="postdetails">前面我们讲到一些OOå’ŒCO的区别。肯定有äºÞZ¸ä»¥äؓ然。什么COåQŸOO包罗万象åQŒä½ æ‰€è°“çš„CO也不˜q‡æ˜¯OO的一个分支而已ã€? <br> <br> <br> 是啊åQŒæ˜“¾lä¹ŸåŒ…罗万象åQŒä¹Ÿè®¸å¤ªæžå›¾æˆ–者伏¾Ÿ²å…­åå››å¦æ—©ž®±å¯ä»¥æ˜q°è’¸æ±½æœºåQŒå–·æ°”战斗机åQŒè®¡½Ž—机åQŒçƒ¤ç«é¸¡åQŒç­‰½{‰ï¼Œæ›´ä½•况什么OOåQŒCO呢? <br> <br> 其实åQŒå¦‚果把OO当作一个大½Ž©ç­åQŒä»€ä¹ˆéƒ½å¾€é‡Œè£…åQŒè‡ªç„Óž¼Œæˆ‘这里要说的也不会蟩出它的藩½‹±ã€‚毕竟我˜q™CO˜q˜æ˜¯ç”¨java实现的呢åQŒå½’根结底,不是˜q˜è¦ç”¨class, interfaceä¹‹ç±»çš„ä¸œè¥¿äØ•æžï¼Ÿ <br> <br> 而我所谈的OOåQŒå’Œè€åº„不同åQŒä¸æ˜¯é‚£ä¹ˆä¸€ä¸ªå®½æ³›çš„æ¦‚念。实际上åQŒæˆ‘说的OO包括两个阶段ã€? <br> <br> ½W¬ä¸€ä¸ªé˜¶ŒDµï¼š <br> <ul>1。认识到数据和行为的¾lŸä¸€æ€§ã€‚用¾cÀL¥ž®è£…数据åQŒéšè—æ•°æ®ï¼Œòq¶ä¸”对行为徏模。这¿Uæ›´é«˜çñ”çš„ADT应该是OO的最基本形态ã€? <br> 2。用¾cȝ‘ô承的方式来渐˜q›å¼åœ°æ˜q°çŽ°å®žç”Ÿ‹zÖM¸­çš„æ¦‚å¿üc€‚对概念之间的差别用子类覆盖父类某一个方法的途径来表达ã€?/ul> <br> <br> 在这个阶ŒDµï¼Œä¼ ç»Ÿçš„“封装,¾l§æ‰¿åQŒå¤šæ€â€å°±å·²ç»è¢«æäº†å‡ºæ¥ã€? <br> <br> ˜q™ç§çœ‹ä¸ŠåŽÕd¾ˆ¾ŸŽçš„非常½W¦åˆäººçš„直觉的方法被äºÞZ»¬å¾ˆå¿«åœ°æŽ¥å—了ã€? <br> <br> 毕竟åQŒPerson, Vehicle, Animal½{‰ç­‰åšæˆ¾cÀL˜¯å¤šä¹ˆç›´ç™½åQŒvehicle.start(), person.work(), animal.eat()看上åŽÀL˜¯å¤šä¹ˆ½Ž€å•ã€? <br> äºÞZ»¬è±¡åƒäº†å–„恶果一样发现眼睛似乎一下子明亮了,世界看上åŽÈ«Ÿç„‰™‚£ä¹ˆåˆ†æ˜Žã€‚靠åQŒè€å­æ€Žä¹ˆæ²¡æ—©çŸ¥é“有这个果子?˜q˜æœ‰æ²¡æœ‰åQŸå†¾l™ä¸¤ä¸ªï¼ <br> <br> 但是åQŒçœŸæ­£åº”用到变化莫测的现实世界,äºÞZ»¬é€æ¸å‘现˜q™ä¸ªæ–ÒŽ³•不象它看上去那么½Ž€å•。多重ç‘ô承的困扰åQŒçˆ¶å­ç±»ä¹‹é—´çš„强烈的耦合都造成了巨大的éºÈƒ¦ã€? <br> 我们¾lå¸¸å‘现åQŒæˆ–者父¾cÀLä¾›äº†å¾ˆå¤šä¸œè¥¿åQŒå¯æˆ‘根本不需要。或者我惌™¦æŸä¸ªä¸œè¥¿åQŒå¯æ˜¯çˆ¶¾cÕdåæ²¡æœ‰è®¾æƒ›_ˆ°˜q™ä¸ªå¯èƒ½åQŒæ²¡æœ‰æä¾›ï¼Œè€Œçˆ¶¾c»è‡ªä½œèªæ˜Žé¢„先设计好的某个设施,不但没用åQŒåè€Œç»™å­ç±»é€ æˆéºÈƒ¦ã€? <br> <br> 于是åQŒå››äººå¸®ä»¬æŒ¯è‡‚高å‘û|¼šä¸è¦ä»¥äØ“OOž®±æ˜¯éšæ„è®¾è®¡ä½ è‡ªå·Þqš„¾c…R€‚你要遵守一定的模式åQ? <br> <br> 于是åQŒäºŒåå‡ ç‰‡æ ‘叶被¾_‘Ö¿ƒ¾~–织成一块遮¾Ÿžå¸ƒé®åœ¨OO的私处上åQŒæˆ‘们真的知道了“善恶”。一个完善的OO道å¯d体系被圣äºÞZ»¬å»ºç«‹äº†è“v来ã€? <br> <br> <br> ½W¬äºŒä¸ªé˜¶ŒDµï¼š <br> 模式真的解放了我们吗åQŸè¿˜æ˜¯æˆ‘们更¾pŠæ¶‚了?曑և ä½•æ—¶åQŒæˆ‘们开始痛恨singletonåQŒé„™è§†template methodåQŒå®³æ€•visitorã€? <br> 是时候该反思一下了。我们真的需要“ç‘ô扎쀝吗åQŸâ€œé‡è½½â€çœŸçš„很好吗åQ? <br> <br> 理论界早ž®±åœ¨ç ”ç©¶subtypeå’Œsubclass的区别,我们发现åQŒä¼¼ä¹Žæœ‰å¿…要区分˜q™ä¸¤ä¸ªæ¦‚念,subtype不见得就必须subclassåQŒç”šè‡»I¼Œ˜qžsubclass也不一定就非得subtypeã€? <br> <br> c++阵营里出çŽîCº†gp的声韟뀂大有一丑ְ†OO˜q™ä¸ªè€æœ½æ‰“翻在地的气åŠÑ€‚模板!到处是模æÑ€‚我们用模板¾l„合模板åQŒä»£æ›¿äº†ä¼ ç»Ÿçš„ç‘ô承,一些äh甚至做出了一些相当技巧性的东西ã€? <br> <br> java跳了出来åQŒåšå®šåœ°æŠŠsubtypeå’Œsubclass分开。于是,我们有了interfaceã€? <br> <br> 所谓interfaceåQŒç†è®ÞZ¸Šž®±æ˜¯ä¸€ä¸ªtype。它和class不同åQŒtype/interface只定义方法的½{‘֐åQŒä½†æ˜¯ä¸åŒ…含具体数据和实玎ͼŒå®ƒåªè¡¨ç¤ºåQšç»™ä½ è¿™ä¸ªç±»åž‹çš„对象后,你能用它来做什么。它不包含:˜q™ä¸ª¾cÕdž‹çš„对象具体是怎么做某一件事的ã€? <br> <br> ˜q™æ ·åQŒclass代表实现åQŒinterface代表规范ã€?implements"代表subtypeåQ?extends"是subclass同时也是subtypeã€? <br> subtypeå’Œsubclass被初步地分开了。我们不再仅仅有几片树叶来遮挡私出,现在我们˜q˜æœ‰äº†braã€? <br> <br> “ç‘ô扎쀝的作用被弱化,甚至被反寏V€‚要求用接口¾l„合来代替ç‘ô承的呼声日高。确实仍然有用ç‘ô承和template method比较方便的场合,但是˜q™ä¸å†å¯¹¾pȝ»Ÿçš„æ•´ä½“æž¶æž„äñ”生媄响。“ç‘ô扎쀝更多地被用作一¿Uå±€éƒ¨çš„实现手段åQŒå®ƒå½±å“çš„不再是整个¾pȝ»Ÿéª¨æž¶åQŒè€Œæ˜¯ä¸‰ä¸¤ä¸ªæœ¬ íw«å°±ç´§å¯†è€¦åˆçš„ç±»ã€? <br> <br> interface的出现在OO内部是一个决定性的事äšg——如果不是一个革命的话ã€? <br> <br> <br> 它进一步完善了OO的“职责分‹z䏀ä½“¾p…R€‚功能的“消费者”和“提供者”可以被明确地区分ã€? <br> <br> 消费者只看见接口åQŒè€Œçœ‹ä¸è§¾c»ï¼Œ˜q™æ ·åQŒç•™ä¸‹äº†ä¸€å—切换不同“提供者”的½Iºé—´ã€? <br> <br> OO的整体哲学甚臌™¢«ä¸Šå‡äº†ä¸€ä¸ªé«˜åº¦ï¼šæˆ‘们不再执著于用树åÅž¾l“æž„åQŒæ¸˜q›å¼åœ°æ˜qîC¸–ç•Œï¼Œå› äØ“æˆ‘ä»¬è®¤è¯†åˆ°è¿™ä¸å¤§å¯è¡ŒåQŒä¸–界比我们惌™±¡çš„要复杂得多ã€? <br> <br> OO在这个阶ŒDµè¢«é‡æ–°è¯ é‡Šä¸ºï¼š<span style="font-weight: bold;">一个责ä»Õdˆ†å·¥ä½“¾p?/span>ã€? <br> 遇到一个问题,我们通过分析需求,把它分解成互相协作的子模块。每个子模块有精¼‹®å®šä¹‰çš„职责。子模块之间通过¾_‘Ö¿ƒè®¾è®¡çš„æŽ¥å£æ¥äº’相通信åQŒåœ¨ä¿è¯æœ€ž®è€¦åˆçš„基¼‹€ä¸Šå®žçŽîCº†åˆ†å·¥åˆä½œã€? <br> <br>所谓iocž®±æ˜¯˜q™æ ·çš„æ€æƒ³çš„一¿Uè¡¨è¾¾ã€‚子模块需要一个外部提供的功能æ—Óž¼Œä¸æ˜¯ç›´æŽ¥åŽÀL‰¾åˆ°æŸä¸ªå…·ä½“实现模块,而是通过接口把协议公开出去。这和上å¸? 他老äh家的设计有点形似了:夏娃需要生儿子åQŒä½†æ˜¯è™½ç„¶æš‚时旁边只有一个adam ggåQŒä½†æ˜¯å¤å¨ƒçš„íw«ä½“构造却不是仅仅为adam设计的,上帝他老äh家给夏娃的是一个跟ä»ÖM½•ç”·äh都能生儿子的通用接口ã€? <br> 女äh˜q™ä¸ªæ¨¡å—的职责被定义为:跟男人(们)生孩子ã€? <br> ç”·äh˜q™ä¸ªæ¨¡å—的职责被定义为:跟女人(们)生孩子ã€? <br> <br> <br> 在这¿Uæ€èµ\æˆäØ“¾pȝ»Ÿçš„主导思想的时候,子模块的¾l„è£…æˆäØ“äº†ä¸€ä¸ªé—®é¢˜ã€‚è°è´Ÿè´£æŠŠé¸¡çŠ¬ç›¸é—»ï¼ˆåªçœ‹è§æŽ¥å£ï¼‰åQŒè€æ­»ä¸ç›¸å¾€æ¥ï¼ˆçœ‹ä¸è§ç±»åQ‰çš„子模块最¾lˆç»„合在一起呢åQŸå½“只有adam夏娃的时候,上帝一努嘴åQŒä¿©äººå°±ç¡ä¸€èµ·äº†ã€‚但是当天下呼呼嚷嚷都是男äh女äh的时候,˜q™å°±ä¸å¤Ÿæ•ˆçŽ‡äº†ã€? <br> 于是åQŒæœˆä¸‹è€ähž®±å¼€äº†ä¸€ä¸ªioc容器åQŒæ¥è´Ÿè´£æŠŠè¿™äº›ç”¨ioc方式设计的组件们用一¿Uæœ€¾læµŽçš„æ–¹å¼æ‹‰åˆîC¸€èµ—÷€? <br> <br> <br> <br> 但是åQŒæœ‰ä¸€ç‚¹ä»ŽOO的前驱PO那里开始到现在都没有变化,那就是,它们始终都是自顶向下的逐渐¾l†åŒ–求精的方法论ã€? <br> <br> <br> ˜q˜æœ‰ä¸€ä¸ªä¸å¤ªäؓ人所å…Ïx³¨çš„共同点åQšä»–ä»?PO, OOåQŒéƒ½æ˜¯å‘½ä»¤å¼çš„。它们都同样以一个状态机的状态变˜qäؓ着眼点来运作系¾lŸã€? <br> <br> 回头看看˜q˜åœ¨ä¸ç”˜å¿ƒåœ°åµåš·ä¸ä¼‘çš„c++çš„gpåQŒå®ƒçœŸæ˜¯ä¸€ä¸ªå•独的æ–ÒŽ³•论吗åQ? <br>它难道不是也通过自顶向下的方法逐步求精åQŸconcept-modeléšùN“不就是interface-class的另一¿Uè¡¨è¾‘ÖŞ式?它难道不是也 åŸÞZºŽçŠ¶æ€å˜˜qçš„命ä×o式系¾lŸï¼ŸåQˆmeta-programming不是åQŒä½†æ˜¯æ­¤å¤„我们暂时不考虑˜q™ç§ç”Ÿæˆå¼ç¼–½E‹ï¼Œå› äؓ它在gp里面òq¶ä¸½Ž—主‹¹ï¼‰ <br> 它难道不是仍然用¾cÀL¥ž®è£…数据åQŒç”¨æ–ÒŽ³•来实现行为? <br> <br> ¼‹®å®žåQŒæ¨¡æ¿å› ä¸ºconcept不是一个强制性的¾cÕdž‹åQŒä“Q何类åQŒåªè¦å…·æœ‰æŸä¸ªconcept要求的函数签名(实际上甚臌™¦æ±‚比˜q™ä¸ª˜q˜è¦æ„¡š„åQ‰ï¼Œž®±å¯ä»¥è¢«å½“作实现˜q™ä¸ªconcept的一个model。如此节省了我们写adapter的工作ã€? <br> 另外åQŒæ¨¡æ¿ç»„合也比基于运行时多态,以来gc的接口组合效率高ã€? <br> 但是åQŒè¿™äº›ç»†æžæœ«èŠ‚åÆˆä¸èƒ½qualify一个单独的æ–ÒŽ³•论ã€? <br> <br> æ‰€ä»¥ï¼Œæˆ‘ä»¬è®¤äØ“åQŒgpå’Œprogramming against interface在方法论上殊途同归,在实现层面上则各有利弊ã€? <br> <br> 好了åQŒçÕQ¾i®å¨å¨è¿™ä¹ˆå¤šåQŒå°±æ˜¯è¦¾l™æˆ‘所谈到和要˜q›è¡Œæ¯”较的“oo”画一个圈子,不能说是“权威定义”,但是åQŒè¿™ž®±æ˜¯æˆ‘要谈的那个“OO”ã€? <br> <br> 下一节开始,我们ž®±å¯ä»¥æ­£å¼å¼€å§‹çœ‹çœ‹æ€Žä¹ˆç”¨CO来解å†Ïxˆ‘前面提出的那个例子ã€? <br> <br> 与此同时åQŒæœ‰å¿ƒäh也可以想想用OOåQˆinheritance-oriented也好åQŒinterface-oriented也好åQ‰è¿™¿Uè‡ª™å¶å‘下的方式怎么实现˜q™ä¸ªéœ€æ±‚繁杂,甚至有些条款˜q˜ä¸¼‹®å®šçš„例子ã€? <br> <br> 我自己是想不出太好的æ–ÒŽ³•。一大堆if-else我不喜欢åQŒçˆ¶å­ç±»ä¹‹é—´æ··äؕ的override˜q™ç§ä¹×ƒëuè¡ŒäØ“æˆ‘ä¹Ÿæœ‰åŠ›ä¸ä»Žå¿ƒä¹‹æ„Ÿã€?/span><img src ="http://www.aygfsteel.com/ajoo/aggbug/27839.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:29 <a href="http://www.aygfsteel.com/ajoo/articles/27839.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论面向组合子½E‹åºè®¾è®¡æ–ÒŽ³• 之一 创世¾U?/title><link>http://www.aygfsteel.com/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.aygfsteel.com/ajoo/articles/27838.html</guid><wfw:comment>http://www.aygfsteel.com/ajoo/comments/27838.html</wfw:comment><comments>http://www.aygfsteel.com/ajoo/articles/27838.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/ajoo/comments/commentRss/27838.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/ajoo/services/trackbacks/27838.html</trackback:ping><description><![CDATA[<span id="wmqeeuq" class="postdetails">新开张。先炒些冷饭˜q‡æ¥ã€‚狡兔三½HŸï¼Œä¸‡ä¸€å“ªå¤©javaeye倒台了(robbin气的脔Rƒ½é’了åQ‰ï¼Œæˆ‘辛辛苦苦码的字ž®×ƒ¸¢äº†ï¼Œž®Þp±¡å½“年在allaboutprogramçš„é­é‡ä¸€æ øP¼Œå“­éƒ½æ‰¾ä¸åˆ°åº™é—¨ã€?br> <br> <br> <br> <br> 发现老庄的连载方法很å¥?又能吸引眼球又能好整以暇.于是从善如流. <br> <br> <br> ˜q™å‡ å¤©åœ¨å®Œå–„我的neptune¾pȝ»Ÿå’Œjaskell语言。顺手发çŽîCº†ä¸€ä¸ªlogging的需求。如莯‚‡³å®é˜¿ã€? <br> <br> ä¸ÞZ»€ä¹ˆå‘¢åQŸä¸æ˜¯å› ä¸ø™¿™ä¸ªéœ€æ±‚多么难åQŒæˆ–者我的解å†Ïx–¹æ³•多么åéyå¦™ï¼Œè€Œæ˜¯å› äØ“åQŒè¿™ä¸ªä¾‹å­èƒö够简单,直观åQŒè¦è¯´æ˜Žå®ƒï¼ŒèƒŒæ™¯çŸ¥è¯†å‡ ä¹Žä¸å¤§éœ€è¦ï¼Œä¸‰ä¸¤å¥è¯å¤§å®¶ž®±æ˜Žç™½éœ€è¦è¾¾åˆîC»€ä¹ˆæ•ˆæžœã€‚è¿™¿Uä¾‹å­å¯ä¸æ˜¯éšä¾¿ž®±æƒ³å¾—到的ã€? <br> <br> 而同æ—Óž¼Œå®ƒåˆå¯¹å®žçŽ°æå‡ÞZº†ä¸€å®šç¨‹åº¦çš„灉|´»æ€§è¦æ±‚,正好方便我展½Cºæˆ‘叫做“面向组合子”的½E‹åºè®¾è®¡æ–ÒŽ³•ã€? <br> <br> <br> 说到˜q™é‡ŒåQŒä¸¼›åˆæœ‰ç‚¹æ²®ä“áåQŒæˆ‘也挺惌™±¡åˆ«äh那样åQŒå…ˆé«˜ä‹D高打åQŒçŽ„ä¹‹åˆçŽ„ï¼Œå¼„äº›å“²å­¦æ€èöLåQŒä»€ä¹ˆä½›æ³•å‘€åQŒé“å¾ïL»é˜¿ï¼Œè¥¿æ¸¸è®îCºšåQŒä»¥åŠå„位西方先哲的亟语åQŒç”šè‡³é‡å­åŠ›å­¦çš„æ‚–è®ºã€‚è¿™æ äh‰èƒ½å¸å¼•眼球,增加人气呀ã€? <br> 可是åQŒç­‰è€Œä¸‹ä¹‹çš„工匠气作¼œŸï¼Œè¯´ç€è¯´ç€ž®Þp¦æ‹åˆ°å…·ä½“例子上去了。不争气呀ã€? <br> <br> <br> ½Ž—了åQŒä¸æƒ³é‚£ä¹ˆå¤šäº†ã€‚论道不是俺˜q™ç§ä¿—äh所擅长的,˜q˜æ˜¯é¼“捣“器”吧ã€? <br> <br> <br> 大致的背景是˜q™æ ·åQ? <br> 我的neptune是一个build systemåQŒåœ¨build的过½E‹ä¸­ä¼šäñ”生很多log信息。这些信息分ä¸ÞZ¸åŒçš„重要¾U§åˆ«ã€? <br> <br> 说到˜q™é‡ŒåQŒè‚¯å®šæœ‰äººå·²¾læŒ‰å¥ˆä¸ä½ï¼šç”¨Log4jåQ? <br> <br> 先不要急,我们˜q™é‡Œä¸æ˜¯è¦å‘Šè¯‰ä½ æ€Žä¹ˆå¤„理你得½E‹åºä¸­çš„logging需求,而是要通过˜q™æ ·ä¸€ä¸ªå®¹æ˜“理解的例子来说明以下“面向组合子”的¾~–程æ–ÒŽ³•。所以,˜q™é‡Œè®©æˆ‘们先假设我们不知道什么log4j。什么是log4jå‘€åQ? <br> <br> 当然åQŒå¤§è‡´çš„æ€èµ\æ€Õd½’差不多的。因为我的neptune¾pȝ»Ÿåªéœ€è¦ä¸€ä¸ªloggingçš„å·¥å…øP¼Œè€Œä¸å…›_¿ƒ˜q™ä¸ªlogging工具是什么,˜q™å°±æ˜¯ä¸€ä¸ªperfect的依赖注ž®„的场合ã€? <br> <br> 先定义接口LoggeråQŒç„¶åŽä»Žæž„造函æ•îC¼ é€’近来一个Logger实例åQŒæŽ¥ç€ž®Þq›´æŽ¥è°ƒç”¨Loggerž®±æ˜¯äº†ã€? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>   <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>   <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 id="wmqeeuq" class="postbody"> <br> <br> print用来输出信息åQŒä½†æ˜¯ä¸æŠ˜è¡ŒåQŒprintln可以折行ã€? <br> logException用来直接¾Uªå½•å¼‚å¸¸ã€‚è¿™æ øP¼Œå¯¹å¼‚常是直接printStackTraceåQŒè¿˜æ˜¯println(e.getMessage())ž®±æ˜¯ç”±å…·ä½“çš„Logger实现来决定,我的neptune只需要把遇到的异常报告给Loggerž®±æ˜¯äº†ã€? <br> <br> <br> 好。接下来我吭哧吭哧地把neptune完成了,剩下的就是从哪里找一个Logger实现了ã€? <br> <br> 最½Ž€å•çš„Logger实现自然ž®±æ˜¯ç›´æŽ¥å¾€å±å¹•上打åîCº†åQ? <br> <br> </span> <table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"> <tbody><tr> <td><span id="wmqeeuq" class="genmed"><b>java代码: </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>   <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     <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>   <span style="color: rgb(0, 0, 0);">}</span> <br>   <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>     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>   <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 id="wmqeeuq" class="postbody"> <br> <br> 直接把这个SimpleLogger注射˜q›æˆ‘çš„neptuneåQŒæ•´ä¸ªç³»¾lŸå°±å¯ä»¥å·¥ä½œäº†ã€? <br> no big dealåQŒå¯¹ä¹ˆï¼Ÿ <br> <br> <br> 好了åQŒä¸‹é¢æˆ‘们开始真正实现完整的logging¾pȝ»Ÿäº†ã€‚经˜q‡åˆ†æžï¼Œæˆ‘们大致有以下的需要: <br> <br> <ul>1。logger可以把信息打印到logæ–‡äšg中ã€? <br><br> 2。不同的重要½E‹åº¦çš„信息也许可以打印到不同的文件中åQŸè±¡websphereåQŒæœ‰error.log, info.log½{‰ã€? <br> 如果˜q™æ ·åQŒé‚£ä¹ˆä»€ä¹ˆé‡è¦ç¨‹åº¦çš„信息˜q›å…¥error.logåQŒä»€ä¹ˆè¿›å…¥warning.logåQŒä»€ä¹ˆè¿›å…¥info.log也需要决定ã€? <br><br> 3。也许可以象ant一æ ähŠŠæ‰€æœ‰çš„ä¿¡æ¯éƒ½æ‰“å°åˆ°ä¸€ä¸ªæ–‡ä»¶ä¸­ã€? <br><br> 4。每条logging信息是否要同时打印当前的¾pȝ»Ÿæ—‰™—´åQŸä¹Ÿæ˜¯ä¸€ä¸ªéœ€è¦æŠ‰æ‹©çš„问题ã€? <br><br> 5。不仅仅是logæ–‡äšgåQŒæˆ‘们还希望能够在标准错误输å‡ÞZ¸Šç›´æŽ¥çœ‹è§é”™è¯¯åQŒæ™®é€šçš„信息可以打印到logæ–‡äšg中,寚w”™è¯¯ä¿¡æ¯ï¼Œæˆ‘们希望logæ–‡äšg和标准输å‡ÞZ¸Šéƒ½æœ‰ã€? <br><br> 6。标准输å‡ÞZ¸Šçš„东西只要通知我们出错了就行,大概不需要详¾l†çš„stack traceåQŒæ‰€ä»¥exception stack trace可以打印到文件中åQŒè€Œå±òq•上有个½Ž€çŸ­çš„exceptionçš„messagež®±å¤Ÿäº†ã€? <br><br> 7。warningä¼ég¹Žä¹Ÿåº”该输出到屏幕上ã€? <br><br> 8。不½Ž¡æ–‡ä»‰™‡Œé¢æ˜¯å¦è¦æ‰“印当前¾pȝ»Ÿæ—‰™—´åQŒå±òq•上应该可以选择不要打印旉™—´ã€? <br><br> 9。客户应该可以通过命ä×o行来军_®šlogæ–‡äšg的名字ã€? <br><br> 10。客户可以通过命ä×o行来军_®šlog的细节程度,比如åQŒæˆ‘们只兛_¿ƒinfo一æ ïLñ”别的信息åQŒè‡³äºŽdebug, verboseçš„ä¿¡æ¯ï¼Œå¯¹ä¸èµøP¼Œä¸è¦æ‰“印ã€? <br><br> 11。neptune生成的是一些Command对象åQŒè¿™äº›å¯¹è±¡è¿è¡Œçš„æ—¶å€™å¦‚果出现exceptionåQŒè¿™äº›exception会带有execution traceåQŒè¿™ä¸ªexecution trace可以告诉我们每个调用栈上的Command对象在原始的neptuneæ–‡äšg中的位置åQˆè¡ŒåøP¼‰ã€? <br> ˜q™ç§exception叫做NeptuneExceptionåQŒå®ƒæœ‰ä¸€ä¸ªprintExecutionTrace(PrintWriter)的方法来打印execution traceã€? <br> 所以,对应NeptuneExceptionåQŒæˆ‘们就不仅仅是printStackTrace()了,而是要在printStackTrace()之前调用printExecutionTrace()ã€? <br><br><br>12。neptune使用的是jaskell语言åQŒå¦‚æžœjaskell脚本˜qè¡Œå¤ÞpÓ|åQŒä¸€ä¸ªEvaluationException会被抛出åQŒè¿™ä¸? ¾cÀLœ‰ä¸€ä¸ªprintEvaluationTrace(PrintWriter)的方法来打印evaluation traceåQŒè¿™ä¸ªtrace用来告诉我们每个jaskell的表辑ּåœ¨è„šæœ¬æ–‡ä»¶ä¸­çš„ä½¾|®ã€? <br> 所以,对应EvaluationExceptionåQŒæˆ‘们要在printStackTrace()之前åQŒè°ƒç”¨printEvaluationTrace()ã€? <br><br> 13。execution traceå’Œevaluation trace应该被打印到屏幕上和logæ–‡äšg两个地方ã€? <br><br> 14。因为printExecutionTrace()å’ŒprintEvaluationTrace()本èín已经打印了这个异常的getMessage()åQŒæ‰€ä»¥ï¼Œå¯¹è¿™ä¸¤ç§å¼‚常åQŒæˆ‘们就不再象对待其它种¾cȝš„异常那样在屏òq•上打印getMessage()了,以免重复ã€? <br><br> 15。也许还有一些暂时没有想到的需求, 比如不是写入logæ–‡äšgåQŒè€Œæ˜¯ç”ÖM¸ªå›¾ä¹‹¾cȝš„变态要求ã€?/ul> <br> <br> 大致上,我目前遇到的需求也ž®±æ˜¯˜q™äº›äº†ã€? <br> <br> 好了åQŒå…è®¸æˆ‘卖个兛_­åQŒä¸‹å›žåˆ†è§£çš„æ—¶å€™å†è¯´æ€Žä¹ˆç”¨â€œé¢å‘组合子”和依赖注射的方法来解决˜q™ä¸ªé—®é¢˜å§ã€? <br> <br> 在本节结束之前,我稍微提一下“面向组合子”的来历ã€? <br> <br> <br>¾l„合子,英文叫combinatoråQŒæ˜¯å‡½æ•°å¼ç¼–½E‹é‡Œé¢çš„重要思想。如果说OO是归¾UÏx³•åQˆåˆ†æžå½’¾U³éœ€æ±‚,然后æ ÒŽ®éœ€æ±‚分解问题,解决问题åQ‰ï¼Œé‚£ä¹ˆ “面向组合子”就是“演¾lŽæ³•”。通过定义最基本的原子操作,定义基本的组合规则,然后把这些原子以各种æ–ÒŽ³•¾l„合èµäh¥ã€‚我最˜q‘一ŒD‰|—¶é—´åšçš„东西, jaskell不用说了åQŒå‡½æ•°å¼è¯­è¨€ã€‚yan, neptune, jparsec全是用面向组合子的思想开发的ã€? <br> <br> OOž®±åƒæ˜¯çŒœè°œï¼Œ¾l™ä½ ä¸€ä¸ªè‹¹æžœï¼Œç„¶åŽé—®ä½ åQšè¿™ä¸ªè‹¹æžœæ˜¯æ€Žä¹ˆå¾—到的呢åQŸç„¶åŽä½ åˆ†æžä¸€ç•ªï¼Œè¯ß_¼šæˆ‘è®¤ä¸ø™¿™ä¸ªè‹¹æžœæ˜¯ç”±åˆ†å­ç»„成的åQŒè¿™äº›åˆ†å­å¦‚此这般排列,然后分子又由原子¾l„成åQŒå¦‚此这般排åˆ?.. <br> <br> 而COåQˆé¢å‘组合子åQ‰ï¼Œž®Þq­‰äºŽæ˜¯è¯ß_¼š˜q™æœ‰H, C, O三种原子åQŒå¼ºå¼×ƒ¸¤¿Uä½œç”¨åŠ›åQŒä½ æ¥çœ‹çœ‹èƒ½åšç‚¹ä»€ä¹ˆå‡ºæ¥å§åQŒç„¶åŽä½ ž®±åƒæ­ç§¯æœ¨ä¸€æ øP¼ŒæŠŠè¿™ä¸‰ç§åŽŸå­åQŒä¸¤¿Uä½œç”¨åŠ›æ­å¾å‡ø™¿™å¤§åƒä¸–界åQŒä»€ä¹ˆæ¯›æ¯›è™«åQŒç‹—熊,周星星,不小心,一下就做出了一个苹果ã€? <br> <br> OO的关键是需求ã€? <br> 所è°?refactor"åQŒä¸˜q‡ä¹Ÿæ˜¯å¼ºè°ƒéœ€æ±‚,让你不要自作聪明地瞎假设需求而复杂化设计。时åˆÈ€çœégºŽå½“å‰çš„éœ€æ±‚ã€‚è¿™æ øP¼Œä¸€æ—¦éœ€æ±‚变æ›ß_¼Œæ‰€‹¹ªè´¹çš„力气可以保证最ž®ï¼Œè€Œä¸”åQŒèˆ¹ž®æ‰å¥½è°ƒå¤´å˜›ã€? <br> 如果需求分析的不好åQŒä¸€åˆ‡å°±æ­‡èœäº†ï¼Œè™½ç„¶å› äؓ一些比如ioc之类的设计方法能让你不至于推到重来,但是需求仍然是重中之重ã€? <br> <br> <br> 那些什么上下文没有åQŒä¸Šæ¥å°±è¯´â€œæ€Žä¹ˆç”¨OO来做一个äh骑èžRå‘€åQŸâ€ï¼Œâ€œæ˜¯äº?éª?è½?å‘€åQŸè¿˜æ˜¯èžR.被骑(äº?åQŸâ€çº¯¾_ÒŽ˜¯æ²¡å¤´æ²¡è„‘地瞎掰ã€? <br> <br> 而CO的关键则是组合子和组合规则的设计。这些组合方法必™å»éžå¸¸ç²¾å·§ï¼Œž®½é‡æ­£äº¤ã€‚组合子的设计既要简单(­‘Šç®€å•才­‘Šå®¹æ˜“被¾l„合åQ‰ï¼Œ˜q˜è¦å®Œæ•´ã€? <br> 比如è¯ß_¼Œå¯ÒŽ•´æ•°è¿™ä¸ªç»„合子åQŒæˆ‘们有+-*½{‰ç»„合方法,˜q™æ ·åªè¦æœ‰äº†0,1˜q™ä¸¤ä¸ªç»„合子åQŒæˆ‘们就可以构造出整个整数世界ã€? <br> 可是åQŒç²¾å·§çš„¾l„合子设计也不是那么å®ÒŽ˜“的。需要有一点点数学的感觉和严密的逻辑思维基础ã€? <br> <br> <br> 有ähè¯ß_¼Œä¸Šå¸æ˜¯ç”¨OO设计的世界,可要我是上帝åQŒæˆ‘宁可用COã€? <br> 设计几个½Ž€å•的基本¾_’子åQŒå‡ ä¸ªç®€å•çš„ç›æ€º’作用力,然后让这些东西自å·Þq»„合,随意发展åQŒä¸æ˜¯æ¯”事必íw¬äº²åQŒå…ˆæƒ³é€å½»äº†è‡ªå·±æƒ³è®©ä¸–界是什么样子,然后一张一张图¾U¸åœ°å…·ä½“设计åQŒä¸€ä¸ªä¸€ä¸ªäh地造, <br> “撒旦,你去òq²åäº‹ï¼Œå¾€æ­ÖMº†æ•´è¿™å¸®è´±äººï¼â€? <br> “天使,你去òq²å¥½äº‹ï¼Œæ‰“个巴掌再给他们点甜枣吃。â€? <br> “儿子,你下åŽÀLØœæ·øP¼Œçœ‹ä¸«æ•¢ä¸æ•¢é’‰æ­ÖM½ åQâ€? <br> 来的å®ÒŽ˜“¾ŸŽå¦™åQ? <br> <br> OO的世界观是一个决定性的机械世界观。你惌™®©ä¸–界是什么样子就要从头一点一ç‚ÒŽœ˜q™ä¸ªæ–¹å‘凑。设计者是全知全能的犹太教上帝耶和华ã€?br> 而CO的世界观是非¼‹®å®šæ€§çš„。我自己设计å‡ÞZ¸€å¥—组合子和组合规则,然后具体˜q™äº›ä¸œè¥¿ä¼šç»„合出什么怪物来我肚子里也没谱。就象James GoslingåQŒä»–设计å‡ÞZº†Java语言åQŒä½†æ˜¯ä»–也没办法预测Java语言都能òq²äº›ä»€ä¹ˆã€‚这是一个希腊宙斯式的,或者中国盘古式的创世纪。世界创造出æ? 了。怎么演化åQŸæˆ‘æ­ÕdŽå“ªç®¡å®ƒæ´ªæ°´æ»”天ã€?br> <br> <br> <br> 哈。终于åŞ而上èµäh¥äº†ï¼Œçˆ½ï¼</span><img src ="http://www.aygfsteel.com/ajoo/aggbug/27838.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/ajoo/" target="_blank">ajoo</a> 2006-01-13 05:17 <a href="http://www.aygfsteel.com/ajoo/articles/27838.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> Ö÷Õ¾Ö©Öë³ØÄ£°å£º <a href="http://" target="_blank">¾¸ÖÝ</a>| <a href="http://" target="_blank">Æ¤É½ÏØ</a>| <a href="http://" target="_blank">ÀÖ¶«</a>| <a href="http://" target="_blank">áÓãôÏØ</a>| <a href="http://" target="_blank">ÌïÁÖÏØ</a>| <a href="http://" target="_blank">³¯ÑôÇø</a>| <a href="http://" target="_blank">DZ½­ÊÐ</a>| <a href="http://" target="_blank">ÆåÅÆ</a>| <a href="http://" target="_blank">·ö·çÏØ</a>| <a href="http://" target="_blank">³µÖÂ</a>| <a href="http://" target="_blank">Ñô½­ÊÐ</a>| <a href="http://" target="_blank">¹âÔóÏØ</a>| <a href="http://" target="_blank">¾Å½­ÊÐ</a>| <a href="http://" target="_blank">¼¨ÏªÏØ</a>| <a href="http://" target="_blank">½¨ºþÏØ</a>| <a href="http://" target="_blank">¹âÉ½ÏØ</a>| <a href="http://" target="_blank">À´·ïÏØ</a>| <a href="http://" target="_blank">ÄÏľÁÖÏØ</a>| <a href="http://" target="_blank">³ç×óÊÐ</a>| <a href="http://" target="_blank">ºº´¨ÊÐ</a>| <a href="http://" target="_blank">¶«º£ÏØ</a>| <a href="http://" target="_blank">¹þÃÜÊÐ</a>| <a href="http://" target="_blank">Ë®³ÇÏØ</a>| <a href="http://" target="_blank">ÂêÇßÏØ</a>| <a href="http://" target="_blank">Î÷ÁÖÏØ</a>| <a href="http://" target="_blank">ÂåÆÖÏØ</a>| <a href="http://" target="_blank">ËÉÑôÏØ</a>| <a href="http://" target="_blank">¶ÁÊé</a>| <a href="http://" target="_blank">ÔªÊÏÏØ</a>| <a href="http://" target="_blank">ÂêÇúÏØ</a>| <a href="http://" target="_blank">°²ÄþÊÐ</a>| <a href="http://" target="_blank">ÎèÑôÏØ</a>| <a href="http://" target="_blank">ÐÏÌ¨ÏØ</a>| <a href="http://" target="_blank">áÓãôÏØ</a>| <a href="http://" target="_blank">»áÍ¬ÏØ</a>| <a href="http://" target="_blank">±¦¼¦ÊÐ</a>| <a href="http://" target="_blank">Í¼Ä¾Êæ¿ËÊÐ</a>| <a href="http://" target="_blank">ÌúÁëÊÐ</a>| <a href="http://" target="_blank">È«½·ÏØ</a>| <a href="http://" target="_blank">À¼¿¼ÏØ</a>| <a href="http://" target="_blank">Û°³ÇÏØ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>