论坛首页 Java企业应用论坛

基础知识: 需求!

浏览 110173 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-08-23  
ajoo ,Ozzzzzz
请原谅我的愚蠢,我真的听不懂你们在真正在讨论什么?

有点如坠五里雾的感觉!可能我真的很笨,但是源代码是最好的文档!
大家可以用源代码说话吗??
0 请登录后投票
   发表时间: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, 那么在这个集合里的各个不同实现之间的差别都是对外界“透明”的。

不知道这可不可以作为一个合适的定义呢?
0 请登录后投票
   发表时间:2004-08-23  
firebody
我们讨论的就是ajoo做法的必要性问题,我认为ajoo的做法是可行的,但是并没发现其必要性。也就是不管你用new也好还是静态工厂也好,你该改变实现就要改变实现,并不能因为你new了就多做点什么,也不会少做了什么。
0 请登录后投票
   发表时间:2004-08-23  
ajoo,你看我这样的认为对不对,我们先不谈优缺点

应用前提(动机)

所有用这个类的外部程序对这个类如何被构造不感兴趣,并且所有应用程序都能适应这样的改变,也就是不管怎样改变构造方法,对任何实用这个类的所有应用程序都不会造成任何不必要的影响、依赖上的问题,外部工厂也可以做到这一点,但你认为静态工厂可以从语言保护上做到


不必要的场合

除了构造方法之外的重构不需要静态方法,也就是如果可以从本类内部实现上重构的


不适合的场合
一个类的构造方式需要因为外部需求发生变化而变化
0 请登录后投票
   发表时间:2004-08-23  
ozzzzzz 写道
ajoo
注意到我对于变化的时候用了“我”这个主语了吗?这只是说明我个人的对于重构的态度,也就是如果不修改我就不会动运行着的代码,当然这只是我的选择。我之所以这样选择,主要是因为外部环境的变化注定会发生,并且往往以我不能掌握的方式发生。也就是我认为你往往没有时间去做内部的驱动的重构,而只能在由于外部驱动的重构的同时考虑内部的结构问题。
不过我倒是要提醒大家重构并不是不会改变接口和行为的,比如f(a,b,c,d)重构为f(A)。(注明:当初有段时间我曾经对此持否定观点,现在改变了)

不错。个人对某些原则得掌握的度都会有所不同。我也不是说我提的重构就是金科玉律。
其实所谓重构也不过是一个工程里总结出来的经验之谈,具体如何掌握还要看项目。

我只是说,如果要用“所有东西都必须由需求变化来驱动”来否定静态厂的作用有点绝对。
0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间: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]
0 请登录后投票
   发表时间:2004-08-23  
ajoo
我从来也没有否认你的静态工厂的意思,我只是还看不到你的静态工厂的效益。从开始到现在一直如此。
0 请登录后投票
   发表时间:2004-08-23  
ajoo
我再次看了你举的例子,我这样理解你的静态工厂代替new 构造器的意思,不知道对不对:

客户端调用HelloImpl.instance()之后就是已经得到一个已经功能完整的对象,不需要再setter ,setter。也不需要中间iOC容器来组装这个对象,你所得到的是 保证对象产生的完整,保证产生的效率!
这个从你一进到javaeye就置疑IoC容器 的观点 应该是吻合的。
你似乎很反对,为了产生一个对象 还需要如此复杂的中间层来 组装这个对象,你反对 一个内聚性的类怎么还需要别的中间层 来帮助产生 !!你认为 产生一个“完整”对象的功能应该是这个对象本身的职责,而为了实现这个职责,你就采纳了静态工厂 论!!


我理解你的意思 对吗如果你认为是这样的话,
那么我我们就 互相 开杀 吧!!
0 请登录后投票
   发表时间:2004-08-23  
引用

但是,这个重构以后我怎么看着还是个singlton。
calc里面用查表法实现还是计算得到,或者计算一次以后存起来,这个不会改变它自己是不是个singlton.因为根据相同的i每次计算得到的值都是一样的。
我并不排斥singlton有内部状态,关键在于这个内部状态是不是外部可区分的。我的看法是如果内部状态能够被外部区分,此时,client只能从接口上区分出来。
这个例子我怎么看着像是在支持我的观点. faint

引用

你说insance对外透明,那么我同样可以将逻辑放到new 构造器中,
客户调用new helloImpl()也一样透明嘛[/b]

看看我上面的总结,如果不是需要改变构造的方式,这是不必要的
例如要把singleton变为非singleton
例如无法在new 里面实现的:
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics