锁定老帖子 主题:IOC, huh?
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-08-12
等听明白了,才发现这不过是DIP和面向接口编程的别名。 如果你不是已经这么做了,那么你根本就不是在对接口编程。 比如我举的那个cache的例子,我的Caching类负责做cache,但是它需要知道怎么构造key,怎么选择方法,这些东西,直接就声明成接口,放在那里等待构造函数传近来就ok了。 所谓type 2, type 3,其实跟IOC本身都没什么关系。在一般情况下,设计任何类时,本着最简化原则,当然都是所有成员声明成final的,然后从构造函数传递进来。因为这样对象的状态数最少,也不用烦心setter和线程安全问题。 而当有些特殊情况,如非常罕见的需要构造循环依赖的情况,自然就不能再final,于是只能通过setter传递进来。 这些,跟IOC有什么直接关系?要说有关系,是不是所有的类设计方法,如singleton, 构造函数,函数重载,范型,adapter都和IOC扯上了亲戚? OO本来就是要尽量让事物独立出来,这样我们可以各个击破。可是怎么大家偏偏喜欢把本来是正交的概念混在一起说呢?开始时髦起encoupling了? 还有一点迷惑不解的是,为什么大家一提到IOC,自然就联系到Pico, Spring等框架? 它们又有什么关系? 我们知道所谓具体依赖抽象,而抽象不应该依赖具体的原则。 那么什么是抽象?自然是这些接口变量,对吗?这样我们不用关心这个变量到底是哪个class。 当然,任何一个程序,无论如何抽象,最终都要具体下来,任何一个对象,不管它的类型是哪个接口,最终都要从一个class new出来。 所以,我们在程序最顶层需要一个无所不知的组装者,静态或者动态地new出所有的对象,然后传递给所有嗷嗷待哺的ioc对象。 而pico, 充当了一个这个最后具体化的组装者角色。它帮助你组建复杂的对象网络。不错,很好。但是那只是辅助ioc设计的一个可选工具而已。根据具体需求,你可以自己new,自己newInstance,使用spring, pico或者MyAssembler, blah blah blah。这个选择都不应该对核心的IOC设计有所影响才对。你的设计是肉,pico等容器不过是个盒子而已。 就象是你可以用一把钳子装一辆车,但是,你的车子设计跟钳子又有什么关系? 汽车设计师们是否要说:“我的设计是基于老虎牌钳子的”? 如果高兴,我用一个改锥+扳手就不能组装这量车了?用一个自动生产线不行吗? 有人喜欢show一些xml的组装配置代码,看上去很cute,但是,那跟你给客户show一个漂亮的对话框有什么本质区别?真正的技术和设计并不体现在你的xml上。一个好的ioc设计可以用xml组装,可以直接在测试代码里用new组装,可以用newInstance组装,可以用工厂方法组装,甚至可以用暂时还没有想到的古怪方法组装。 pico是抽象还是具体?它负责创建对象,自然是具体,对不对? 同样根据dip原则,你的代码不应该依赖于具体,于是也就不应该依赖于pico。 所以,如果你在设计你的系统的时候到处考虑甚至使用pico,我想那真是可怕的误会。概念上那根本就不是ioc设计,你在依赖“具体”了! 理想的设计里,大部分代码应该是根本不知道pico为何物的,只关心各自的业务逻辑就好了。pico相关的代码,应该只出现在负责组装整个系统的那个小单间里。 pico,可能是个很好的做ioc的工具,就象ant+junit可以帮助你做自动化测试。但是,你的代码质量,设计质量不取决于你是否在代码里使用了pico,实际上,你在核心代码里引用了pico, ant或者junit的api?完了,你的设计很可能是个一塌糊涂的错误! 不是因为你用了pico, spring你就IOC了。是因为你用了IOC才需要pico或者类似的组装技术。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-08-12
引用 理想的设计里,大部分代码应该是根本不知道pico为何物的,只关心各自的业务逻辑就好了。 真是奇怪,pico,spring就能让你达到这点啊,在使用type2,type3的情况下,业务代码根本不知道容器的存在 你用ioc为指导做了实际项目没有 与aop不同,ioc我认为是每个开发者应该接受并主动去运用的 |
|
返回顶楼 | |
发表时间:2004-08-12
引用 pico,spring就能让你达到这点啊
这句话有点矛盾呀。哪点?就是根本不知道pico, spring为何物? 这在任何得ioc设计都是很自然的,我为什么需要pico/spring才能进行ioc设计? 没有它们我就达不到这点?没有pico/spring我的代码就得依赖pico/spring? 这话怎么嚼怎么嚼不出味道来。 |
|
返回顶楼 | |
发表时间:2004-08-12
关键问题是:
ioc设计需要pico, spring吗?没有它们我不能做ioc设计吗? |
|
返回顶楼 | |
发表时间:2004-08-12
引用 你用ioc为指导做了实际项目没有
听起来好像在pico/spring出来之前就没有dip, 没有对接口编程,没有ioc一样。 ioc是pico等框架的专利吗? |
|
返回顶楼 | |
发表时间:2004-08-12
ajoo 写道 引用 你用ioc为指导做了实际项目没有
听起来好像在pico/spring出来之前就没有dip, 没有对接口编程,没有ioc一样。 ioc是pico等框架的专利吗? ajoo这问题就问得有点蛮不讲理了。Martin Fowler那篇Dependency Injection不是老早说了吗,这不是什么新鲜玩意,Pico/Spring只不过是还算不错的两个实现罢了。往前两年,我们不是也还有Avalon吗? |
|
返回顶楼 | |
发表时间:2004-08-12
ajoo是不是想说我们的业务逻辑不应该依赖于spring或者pico呢?
你可以自己再封装一层,使你的业务逻辑远离spring或者pico spring和pico就是个工具吗,就好像你需要抽烟,spring就像一个打火机,当然你不想依赖于打火机,也可以钻木取火 |
|
返回顶楼 | |
发表时间:2004-08-12
albert_qhd 写道 ajoo是不是想说我们的业务逻辑不应该依赖于spring或者pico呢?
你可以自己再封装一层,使你的业务逻辑远离spring或者pico spring和pico就是个工具吗,就好像你需要抽烟,spring就像一个打火机,当然你不想依赖于打火机,也可以钻木取火 这个比方好 JUnit还没有出来时,单元测试的概念还是有的,JUnit推进了这个思想,并扩展到各个语言平台,ioc也是一样, |
|
返回顶楼 | |
发表时间:2004-08-13
用打火机和抽烟来比喻很形象。只是我对pico/spring和ioc的关系是否有这么密切表示怀疑。
ioc就是dip,在几乎任何时候我们都应该遵循这样的原则。那是接口编程的基础。 但是我们时时刻刻都需要一个容器框架吗? 无论pico也好,spring, avalon也好,没有这些框架,ioc原则的应用有什么困难呢? 当然,大系统的最后的组装可能比较麻烦,很多系统都需要xml文件进行配置。可是,我们能说ioc就联系到xml配置文件吗?归根结底,这是两个根本不同的概念啊。 我不是反对使用框架,而是说,在编写你的业务逻辑的时候,根本就不用关心什么框架,什么spring, pico,跟我有什么关系? 写完了业务核心,负责组装或者部署的人去为使用什么框架烦心吧,我度假去咯! 如果业务逻辑的编写要受到选择的组装框架的影响(即使我可以自己再写抽象封装),那么这里面就有问题。 而象albert说的,正是我所不解的 引用 你可以自己再封装一层,使你的业务逻辑远离spring或者pico
这是所谓的“当然你不想依赖于打火机,也可以钻木取火”的意思吗? 如果这样,那么我不解。香烟天然就根本不需要依赖打火机。用打火机还是钻木都是点烟的小弟的责任,作为大哥的我,为什么要为了抽一只不依赖打火机的香烟而自己钻木取火? 为什么我要额外做工作来使我本来不关心某项东西的代码“远离”那个东西? 为什么你部署者选择的部署组装框架会对我的业务代码开发有所影响?这不是一个不应该有的依赖关系吗? 在我看来,一个好的ioc设计应该闭口不谈spring, pico等容器,因为我和它们无关,是正交的。而不是一提ioc就是spring/pico。 你在你的业务代码里面需要用到pico/spring/avalon的api吗?需要import它们的package吗? 如果需要,为什么? 如果不需要,那么ioc设计和pico等的关系就是正交的。讨论ioc设计而不是组装的时候就没有pico们什么事。 |
|
返回顶楼 | |
发表时间:2004-08-13
举个例子吧,我的一个业务类BusinessImpl,需要一个Persistence的功能,怎么办?ioc,定义一个接口,声明一个成员变量,让组装者给我传递进来:
interface Persistence{ void store(Object o);; } final class BusinessImpl{ private final Persistence pers; public void f(...);{ ... pers.store(obj);; } BusinessImpl(Persistence p);{pers = p;} }; 这是一个ioc设计吧?需要关心pico吗?需要调用什么PicoContainer吗? 再有一个BusinessBImpl,需要一个用几个部件组装成一个对象的功能。怎么办?ioc。定义工厂接口。声明接口成员,让构造函数传进来。 interface Builder{ public Object build(int i, String name);; } final class BusinessBImpl{ private final Builder builder; public Object f(...);{ ... return builder.build(i, name);; } BusinessBImpl(Builder b);{ builder = b; } }; 是ioc设计么?需要知道什么pico么? 如此一层一层地ioc下去,我什么地方需要知道我的组装者采用了一个古怪的叫做"pico"的玩艺儿来给我注射我需要的所有实现呢?除非我要自己去研究组装技术,否则我为什么要知道pico?我不能在根本不知道什么pico的情况下快乐地ioc下去吗? 我不能在组装者跑来小心翼翼,忧心忡忡地询问:“大哥,我发现了一个新的叫做poop的组装框架,cool极了!我能不能用它来代替现在用的pico?不会影响你吧?”的时候,大声地告诉他:“get out of here!你用什么组装关我屁事?别影响我打牌,就差5分就升级了!”? 反过来,如果你的BusinessBImpl的代码使用pico,换成这样: final class BusinessBImpl{ private final String classname; public Object f(...);{ ... return PicoContainer.newPicoInstance(classname);; } BusinessBImpl(String name);{ classname = name; } }; 完了,你的设计已经不是ioc了。你依赖于具体的PicoContainer。组装者一旦想换成PoopContainer,你的代码就要改。 其实这样的代码和jndi的方式有什么本质不同?不过是打着ioc招牌的传统面向实现的东西。 |
|
返回顶楼 | |