锁定老帖子 主题:基础知识: 需求!
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-08-23
ajoo ,Ozzzzzz
请原谅我的愚蠢,我真的听不懂你们在真正在讨论什么? 有点如坠五里雾的感觉!可能我真的很笨,但是源代码是最好的文档! 大家可以用源代码说话吗?? |
|
返回顶楼 | |
发表时间:2004-08-23
好啊。 举个例子吧:
客户:老哥,我要你给我实现一个东西,这个东西可以在屏幕上打印字符串"x1"。 张三:好。根据您的要求,这是正式的语义描述,您是否认可? 1。当被调用,这个模块在标准输出上打印字符串"x1" 2。这个模块不再标准输出和任何其它输出文件上打印其它任何东西。它不对任何其它的程序的模块状态有任何影响。 3。这个模块将在O(1)时间完成,没有等待。 4。程序的event log不在要求范围内。外界用户不要假设每次创建的都是一个新的对象。外界用户不要关心生成的实例的具体类信息。 客户:好的。 那么,什么是透明? 只要我的实现能够做到1(即做什么), 并且达到2(即不作什么),达到3(复杂度要求),达到4(明确确定外界所关心的语义范围) 就是符合要求的。 于是, class HelloImpl implements Hello{ public void sayHello();{System.out.println("x1");;} private HelloImpl();{} public static Hello instance();{return new HelloImpl();;} }是符合要求的。 class HelloImpl implements Hello{ private HelloImpl();{} public static Hello instance();{ return new GenericHello(System.out, "x1");; } } 是符合要求的 class HelloImpl implements Hello{ private final Log log; public void sayHello();{ log("sayHello");; System.out.println("x1");; } private HelloImpl();{ log = SystemFacade.getStandardLogInstance();; } private static final Hello singleton = new HelloImpl();; public static Hello instance();{return singleton;} } 仍然是符合要求的。 这个列表可以一直列下去。 如果我们把所有符合上述语义要求的实现可能性作为集合A, 那么在这个集合里的各个不同实现之间的差别都是对外界“透明”的。 不知道这可不可以作为一个合适的定义呢? |
|
返回顶楼 | |
发表时间:2004-08-23
firebody
我们讨论的就是ajoo做法的必要性问题,我认为ajoo的做法是可行的,但是并没发现其必要性。也就是不管你用new也好还是静态工厂也好,你该改变实现就要改变实现,并不能因为你new了就多做点什么,也不会少做了什么。 |
|
返回顶楼 | |
发表时间:2004-08-23
ajoo,你看我这样的认为对不对,我们先不谈优缺点
应用前提(动机) 所有用这个类的外部程序对这个类如何被构造不感兴趣,并且所有应用程序都能适应这样的改变,也就是不管怎样改变构造方法,对任何实用这个类的所有应用程序都不会造成任何不必要的影响、依赖上的问题,外部工厂也可以做到这一点,但你认为静态工厂可以从语言保护上做到 不必要的场合 除了构造方法之外的重构不需要静态方法,也就是如果可以从本类内部实现上重构的 不适合的场合 一个类的构造方式需要因为外部需求发生变化而变化 |
|
返回顶楼 | |
发表时间:2004-08-23
ozzzzzz 写道 ajoo
注意到我对于变化的时候用了“我”这个主语了吗?这只是说明我个人的对于重构的态度,也就是如果不修改我就不会动运行着的代码,当然这只是我的选择。我之所以这样选择,主要是因为外部环境的变化注定会发生,并且往往以我不能掌握的方式发生。也就是我认为你往往没有时间去做内部的驱动的重构,而只能在由于外部驱动的重构的同时考虑内部的结构问题。 不过我倒是要提醒大家重构并不是不会改变接口和行为的,比如f(a,b,c,d)重构为f(A)。(注明:当初有段时间我曾经对此持否定观点,现在改变了) 不错。个人对某些原则得掌握的度都会有所不同。我也不是说我提的重构就是金科玉律。 其实所谓重构也不过是一个工程里总结出来的经验之谈,具体如何掌握还要看项目。 我只是说,如果要用“所有东西都必须由需求变化来驱动”来否定静态厂的作用有点绝对。 |
|
返回顶楼 | |
发表时间:2004-08-23
ajoo 写道 charon, 确实,准确的说法应该是“可观测语义”。
其实最精确的说法,也许应该是:“相对观测模块的可观测语义”。 比如说, log, 这个动作是副作用,有和没有是不同的。 但是如果用这个相对的可观测语义,只要外界调用者对是否存在log不关心,那么这其实也算是一个可观测语义的透明。 对于你提出的这个“增加了成员变量必然也改动了接口”,我想一个比较合适的用例可能是cache。在开始,我可能为了简单,直接实现,所以不需要任何状态。 而后来如果我想做一个cache以提高效率,那么就需要一个局部状态。 比如: interface Calc{ int calc(int i);; } class CalcImpl implements Calc{ public int calc(int i);{ //do some very complex calculation return r; } ... public static Calc instance();{return singleton;} } 这是第一版。 在第二版,我注意到计算非常耗时,也许可以通过cache来提高效率。 于是,我可以加一个HashMap来缓存一些计算结果。这时我可能就会想给对象加入局部状态。于是,singleton就不合适了。 更合适的例子,我还要再想想。 但是,这个重构以后我怎么看着还是个singlton。 calc里面用查表法实现还是计算得到,或者计算一次以后存起来,这个不会改变它自己是不是个singlton.因为根据相同的i每次计算得到的值都是一样的。 我并不排斥singlton有内部状态,关键在于这个内部状态是不是外部可区分的。我的看法是如果内部状态能够被外部区分,此时,client只能从接口上区分出来。 这个例子我怎么看着像是在支持我的观点. faint |
|
返回顶楼 | |
发表时间:2004-08-23
ajoo 写道 好啊。 举个例子吧:
客户:老哥,我要你给我实现一个东西,这个东西可以在屏幕上打印字符串"x1"。 张三:好。根据您的要求,这是正式的语义描述,您是否认可? 1。当被调用,这个模块在标准输出上打印字符串"x1" 2。这个模块不再标准输出和任何其它输出文件上打印其它任何东西。它不对任何其它的程序的模块状态有任何影响。 3。这个模块将在O(1)时间完成,没有等待。 4。程序的event log不在要求范围内。外界用户不要假设每次创建的都是一个新的对象。外界用户不要关心生成的实例的具体类信息。 客户:好的。 那么,什么是透明? 只要我的实现能够做到1(即做什么), 并且达到2(即不作什么),达到3(复杂度要求),达到4(明确确定外界所关心的语义范围) 就是符合要求的。 于是, class HelloImpl implements Hello{ public void sayHello();{System.out.println("x1");;} private HelloImpl();{} public static Hello instance();{return new HelloImpl();;} }是符合要求的。 class HelloImpl implements Hello{ private HelloImpl();{} public static Hello instance();{ return new GenericHello(System.out, "x1");; } } 是符合要求的 class HelloImpl implements Hello{ private final Log log; public void sayHello();{ log("sayHello");; System.out.println("x1");; } private HelloImpl();{ log = SystemFacade.getStandardLogInstance();; } private static final Hello singleton = new HelloImpl();; public static Hello instance();{return singleton;} } 仍然是符合要求的。 这个列表可以一直列下去。 如果我们把所有符合上述语义要求的实现可能性作为集合A, 那么在这个集合里的各个不同实现之间的差别都是对外界“透明”的。 不知道这可不可以作为一个合适的定义呢? 针对你举的这个例子,我提出我的疑问或者辩驳:如果我这样设计: public class HelloImplA implements Hello{ public HelloImplA();{ } public void sayHello();{ // .. } }; public class HelloImlB implements Hello{ public HelloImlB();{ } public void sayHello();{ //.... } }; //客户端直接调用new HelloImplA();.sayHello();; //这和你的HelloImplA.instance();.sayHello();有何区别?看不出insance存在 //的必要性 为了更好的符合我们组装bean的习惯,我还可以这样做设计: public class HelloImpl implements Hello{ private Delegater delegater=new DelegatorIimpleA();; //default //setter getter for delegator public void sayHello();{delegater.hello();} public HelloImpl();{ } } public interface Delegater implements Hello{ public void seyHello{ } } public class DelegaterA implements Delegeter{ public void sayHello();{ //do something system.out.println("heelo');; } }; 那又如何??? 从你举的例子来看,我实在看不出你的instance 静态方法有何好处 你说insance对外透明,那么我同样可以将逻辑放到new 构造器中, 客户调用new helloImpl()也一样透明嘛[/b] |
|
返回顶楼 | |
发表时间:2004-08-23
ajoo
我从来也没有否认你的静态工厂的意思,我只是还看不到你的静态工厂的效益。从开始到现在一直如此。 |
|
返回顶楼 | |
发表时间:2004-08-23
ajoo
我再次看了你举的例子,我这样理解你的静态工厂代替new 构造器的意思,不知道对不对: 客户端调用HelloImpl.instance()之后就是已经得到一个已经功能完整的对象,不需要再setter ,setter。也不需要中间iOC容器来组装这个对象,你所得到的是 保证对象产生的完整,保证产生的效率! 这个从你一进到javaeye就置疑IoC容器 的观点 应该是吻合的。 你似乎很反对,为了产生一个对象 还需要如此复杂的中间层来 组装这个对象,你反对 一个内聚性的类怎么还需要别的中间层 来帮助产生 !!你认为 产生一个“完整”对象的功能应该是这个对象本身的职责,而为了实现这个职责,你就采纳了静态工厂 论!! 我理解你的意思 对吗如果你认为是这样的话, 那么我我们就 互相 开杀 吧!! |
|
返回顶楼 | |
发表时间:2004-08-23
引用 但是,这个重构以后我怎么看着还是个singlton。 calc里面用查表法实现还是计算得到,或者计算一次以后存起来,这个不会改变它自己是不是个singlton.因为根据相同的i每次计算得到的值都是一样的。 我并不排斥singlton有内部状态,关键在于这个内部状态是不是外部可区分的。我的看法是如果内部状态能够被外部区分,此时,client只能从接口上区分出来。 这个例子我怎么看着像是在支持我的观点. faint 引用 你说insance对外透明,那么我同样可以将逻辑放到new 构造器中, 客户调用new helloImpl()也一样透明嘛[/b] 看看我上面的总结,如果不是需要改变构造的方式,这是不必要的 例如要把singleton变为非singleton 例如无法在new 里面实现的: |
|
返回顶楼 | |