锁定老帖子 主题:pico印象
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-24
既然你用过pico,正好,比较一下我正在做文档的一个micro container的示例。
我对照着pico来写,这样可以省好多解释: pico: pico.registerComponentImplementation(X.class);; yan: yan.registerConstructor(X.class);; pico: pico.registerComponentImplementation("x", X.class);; yan: yan.registerConstructor("x", X.class);; pico: pico.getComponentInstance("x");; yan: yan.getInstance("x");; pico: pico.getComponentInstanceOfType(X.class);; yan: yan.getInstanceOfType(X.class);; 目前为止,都是换汤不换药。 但是pico的提供的用户定制能力实在有限,下面看看一些定制: pico: pico.registerComponentImplementation(X.class, new Parameter[]{new ConstantParameter("1st param");, new ComponentParameter(Y.class);});; 这个pico代码告诉容器第一个参数用"1st param"字符串,第二个参数用另外一个Y.class的组件。 yan: yan.registerComponent( Components.ctor(X.class);.withArguments(new Component[]{ Components.value"1st param");, Components.useType(Y.class); }););; 这里的Component就相当于ComponentAdapter了。只不过它的接口瘦一点。 还是差不多是吗? 但是,pico的能力基本到此就截止了。你要再灵活一点,自己写Parameter的实现吧。没有什么代码可以重用。 比如,我的第一个参数想调用某个函数,用它的返回值,第二个参数是一个数组,想用component Y, Z产生的实例来作为它的元素。 对应的java代码如下: new X(A.getString();, new Object[]{getInstanceFor(X.class);, getInstanceFor(Y.class});; pico怎么办?自己吭哧吭哧写Parameter实现吧。 对比yan: yan.registerComponent( Components.ctor(X.class);.withArguments(new Component[]{ Components.static_method(A.class, "getString");, Components.array( Components.useType(Y.class);, Components.useType(Z.class); ); }););; 转一句文,yan基于的是组合子逻辑。它围绕Component提供了一套组合能力,这样大多数的需求都可以通过组合若干个简单的Component来达到。 比如, Components.bean( Components.method(obj, "calculate"); .withArgument(0, Components.value(new Integer(1););); .withArgument(3, Components.useKey("x3");); );. withProperty("map", Components.hashmap(new String["key1", "key2"], new Component[]{ Components.useKey("component1");, Components.useKey("component2"); } ); );.singleton();; 用伪码解释,上面的意思是: r = run obj.calculate with first parameter as 1, 3rd parameter using component x3. call the java bean setters of object r. for property named "map" create a HashMap object get instances for component1 and component2 populate the map using "key1", "key2" as key, the instances from component1 and component2 as value. call the setter to set this HashMap instance. return r as singleton. 可以看到,组件的创建,是用构造函数,还是用静态方法,还是用随便的一个函数调用,都随便。容器不做任何强迫。 同样,用setter injection也可以。 其它还有一些更强大的组合子,如map, bind等。bind涉及到monad,不解释了。 map可以解释一下: Components.useKey("abc");.map(new Map();{ public Object map(Object obj);{ return ""+obj; } public Class getType();{return String.class;} });; 这个Component在创建对象时,会先调用component abc,然后把返回的对象转换为字符串。 利用map的功能,扩展和代码重用就更容易了。 比如,核心只提供了生成ArrayList和LinedHashMap的组件。但是,如果你想要某个组件返回MyList,大可以用一个map,把一个返回ArrayList的组件的返回值变换成MyList。 对了,还有lifecycle没说。 yan的lifecycle不是侵入式的。而且,实现上,yan的核心根本就不依赖lifecycle,它就不知道lifecycle这回事。这样保证了单一职责和简单性。 在核心之上,有一个支持lifecycle的插件。这个插件缺省支持init, start, stop, dispose等。但是你也可以提供任何其它的lifecycle。 示例如下: YanContainer yan = ...; yan.registerComponent("connection", LifecycleHelper.instance( Components.static_method(ConnectionFactory.class, "createConnection" ); );.initializer("connect");.disposer("close"); .get(); );; 这个就相当于spring的: <... init-method="connect", destroy-method="close"/> 最后,如此调用: new DefaultLifecycle(yan);.init();; new DefaultLifecycle(yan);.dispose();; |
|
返回顶楼 | |
发表时间:2005-03-24
先答第二部分Life Cycle的,我也支持你这么做
我用Pico的话也要在我真正的对象上架上一层来隔离Pico对我业务对象的侵入,这样讨论下来,的确Pico的LifeCycle还是简陋得多了。 我的理解总结一下: 用Pico 应用程序 ---- Pico生命周期的隔离层 ----- 业务对象 用Yan 应用程序 ---- DefaultLifecyle() ----- 业务对象 我猜测你的DefaultLifecyle()也是一个Interface下面的实现。 其中业务对象又是在Pico或者Yan中容纳的对象。 我想大体上可能都是异曲同工。关于第一个问题,我稍后有时间多考虑一下回答你。 达成的共识是,Pico还是有些丑陋:D PS: Yan????莫不是阳? |
|
返回顶楼 | |
发表时间:2005-03-24
DefaultLifecycle目前还没有接口。因为没有发现需要。
它和pico不同的是,它是容器的外围插件,容器核心不依赖于它。它负责给容器提供一个常见的lifecycle解决方案。它不对组件做任何要求,业务对象不需要继承任何类,或者实现任何接口。 工作原理是这样: 容器核心支持对所有容器生成的实例进行遍历。 在遍历时候调用用户传入的回调。这个回调会拿到这个实例以及生成这个实例的Component。 每个Component都可能带有一个用户指定的状态对象,这个状态可以是任意的Object,容器核心不作规定。 DefaultLifecyle和LifecycleHelper作为围绕在外围的应用,用一个hash table来作为组件的状态。这样,当LifecycleHelper登记不同的方法的时候,它只不过把这个方法存入hash table。 DefaultLifecycle在遍历组件实例的时候就查询这个hash table,调用预定义了名字的方法。 我现在基本测试完毕,偷了好多pico的test case,嘿嘿。但是文档写起来比较麻烦。加上我还要抓紧测试我的jaskell和parsec。所以暂时没有时间发布。 对了,再批评pico的容器继承。 pico的容器继承和它的lifecycle一个毛病,都直接写在容器核心里面。DefaultPicoContainer又负责登记组件,又负责遍历实例,又负责处理继承关系,很显然内聚不够。 而且pico的继承关系比较死,a继承b就是a继承b。不能a继承b又继承c。也不能a继承b,b也继承a。 yan的继承关系的管理(虽然我还有点怀疑这个继承在yan里面是否有必要)是独立的模块。一个单独的InheritedContainer类负责管理单一继承,如果高兴,我们也可以支持多重继承,写个MultiInheritanceContainer类就是。 a.inherit(b)并不改变a,它采用immutable设计,生成一个新的container,这个container体现a继承b这个关系。 于是,如果我们说: c1 = a.inherit(b); c2 = a.inherit(c); c3 = b.inherit(a); 我们就同时得到三个不同的继承关系: c1代表a继承b c2代表b继承a c3代表a继承c 这也是一个我自觉比pico强的地方。 |
|
返回顶楼 | |