锁定老帖子 主题:我也来发邮件
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-04-02
面向对象的思维方法》,有感而发,也想谈谈自己的从面向对象的角度出发,发邮件的思路。
看了Robbin的《先设定一个环境,假设Java视线论坛,要组织一个活动,需要给每个会员发送通知,这个目标,用面向对象的思路应该如何实现? 1、什么是对象? 这个问题太大,其实我要问的问题可以缩小成为:“在我前面设定的这个环境中,哪些是对象?”同时还要补一句,“哪些不是对象?” 各位可能看到这里,就已经不能同意我的说法了,“哪些不是对象?”,按照面向对象的思路,不是一切都是对象吗? 我必须承认,我的思路,并不和大家一样,我认为把一切都看成对象,是面向对象可能带给初学者最大的误导。真的,有很多东西,并不是对象。虽然在Java里面,我们用class来放置所有的程序。 那么什么不是对象呢?只做某些事的某个“东西”,就不是对象,而是模块。在jdk中,有很多class,里面存在static的属性和函数,这些东西,其实就是过去的面向过程的程序中的模块,没有任何实质区别。有人会说,那么这个对象里还有属性数据呢?面向对象与面向过程的最大的区别就是数据和程序封装到一个对象里啊?但是,在我看来,这样的对象里的数据,其实就是作用域在这个模块里的变量而已。 我们从语义学上来区分一下:“消息”和“命令”。将一个消息传递给一个对象,而将一个命令传递给一个功能模块。传递消息的意义是:“我能对他做什么。”,传递命令的意义是:“我能叫他做什么。” 我能对他做的事情,是他对外提供的接口,我可以通过这个接口,给他消息,至于他会如何处理这个消息,我无从知道。 我能叫他做的事情,是他对外提供的功能,这意味着,我知道我这个命令会实现什么样的效果。 从面向对象的纯粹的含义上来说,一个真正的对象,我应该只知道——我能对他做什么。所以在这个环境中,只有注册用户和管理员,是对象,至于发邮件的那个功能,那就是一个功能而已。 2、什么是对象? 有没有搞错,再问一遍,标题重复了吧?没有,这个问题的意义在于,我们经常会混淆现实生活中的对象,与程序中的对象。现实生活中,庄表伟自然是一个对象,而在这个论坛里,还有一个程序意义上的Class User,以及一个User对象的实例,这个实例的UserID=2976,代表我在这里的身份。 这个实例的本质是什么呢?是一个我在这个社区的代理,这个代理的作用是双向的,一方面我在登录之后,可以向这个实例发送消息,让它代替我在这个社区里行走,浏览文章,发表文章,另外一方面,其他的用户,也可以对这个实例发送一些消息,在他们看来,这个实例就能够代表我(注:代表那个在社区里活动的我)。比如说:“给我发送消息,发送邮件,赠送金币,或者封我的权限等等。” 那么,什么不是对象呢?那个在现实生活中找不到对应的,就不是对象。我们常常为了强迫自己具备面向对象的思维,而将发邮件这样的“功能模块”,也看成对象,然后在脑子里想象着,有那么一个小人,在接收我的命令,然后帮我发邮件。 3、如何发邮件呢? 现在这个问题就非常简单了,一个User的实例,可以接收sendMail()这样的消息,这个消息是由管理员的对象实例传给他的。(当然AdminUser是一个继承了User的类)。至于这个邮件是不是真的能发到用户那里,不但要看管理员有没有给他发送消息,还要看,这个用户是不是设定过,愿意接收邮件通知这样的属性。当然,这个设定,管理员是可以不管的。 然后呢?没有然后了。事情到这里,面向对象的活就干完了。剩下的活,就是面向过程的活了。 如何发出一堆邮件呢?这是管理员需要考虑的麻烦:) 好吧,我们也来帮他想一想这个问题,他需要得到一个用户的list。这个得到list的过程,应该由系统的某一个函数来完成,这个函数无论返回什么结果类型,都不过是一个代码上的约定,Robbin说,Iterator这样的接口,要比Vector这样的具体的类要好。但是在我看来,Robbin说的Vector“违反了面向对象设计的一个原则:在设计的时候不应过早的考虑具体程序语言的实现。”而Iterator也同样违反这个原则。当然,从编程的角度来说,Iterator要比Vector要好,但是这样的好,并不是面向对象意义上的好,而是开发时“适度超前设计,有利于今后维护”这样的好。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-04-02
补充:我前面在写的那篇分析面向对象的文章,还没有写完,在那篇文章里,我会详细的解释,为什么当前流行的面向对象的思想是有缺陷的,进而为什么会产生AOP这样的思想。
|
|
返回顶楼 | |
发表时间:2004-04-02
引用 那么,什么不是对象呢?那个在现实生活中找不到对应的,就不是对象。我们常常为了强迫自己具备面向对象的思维,而将发邮件这样的“功能模块”,也看成对象,然后在脑子里想象着,有那么一个小人,在接收我的命令,然后帮我发邮件。
绝对了吧??你可以把 “发邮件” 当成一个代理,给这个代理一个消息,让他发给谁谁一封信。至于这个代理如何发送,当然才是过程的事情了。 在我看来, 纯粹bean 形式的类,自然对应的就是对象 |
|
返回顶楼 | |
发表时间:2004-04-02
sim114 写道 绝对了吧??你可以把 “发邮件” 当成一个代理,给这个代理一个消息,让他发给谁谁一封信。至于这个代理如何发送,当然才是过程的事情了。
在我看来, 纯粹bean 形式的类,自然对应的就是对象 有这样几种对象,在java里面,他们都是类。但是是有区别的。 一种就是你说的纯粹的bean。这当然是对象。 还有一种是以前概念里的模块(函数),现在也叫对象。 还有一种是消息,这是在对象与对象之间通信用的,现在也叫对象。 但是,真正能够和现实世界对应的是:纯粹的bean类的对象。其他的对象,只是因为我们用的是java语言,因此需要用class xxxx { }来定义而已。 至于你说的,可以把“发邮件”当成一个代理。但是,请问:“发邮件这个动词,怎么能够被看成一个代理这样的名词?” |
|
返回顶楼 | |
发表时间:2004-04-02
我不赞同楼主的意见。
"发邮件"是一个过程没错,在java中可能是一个方法或一系列方法的组合。 不过在现实中我们是怎么发送邮件的呢?是通过邮局,那么我们也可以在系统中定义这样的一个邮局对象,"发邮件"就是这个邮局对象的一个方法。现实中的事情处理都是由人或机构或机器等等来处理,应该是可以抽象出对象来的。 |
|
返回顶楼 | |
发表时间:2004-04-02
像 xxxUtils 这种我当然承认是模块,功能函数而已,也从没把他当过对象看。
引用 还有一种是消息,这是在对象与对象之间通信用的,现在也叫对象。
这种你说的应该是类似 VO的对象,像这里说的那封信应该就是吧,我也认为不是真对象,但是就没有通信的对 象存在的? 引用 至于你说的,可以把“发邮件”当成一个代理。但是,请问:“发邮件这个动词,怎么能够被看成一个
代理这样的名词?” 用词错误,发邮件的机构 仔细想了想,好像你说的也满有道理的,可是就觉得不太对劲。转不过来了. 对我们广大老百姓来说,发邮件的机构 的的确确 是一个中立的物体,因此邮局就是一个模块!!!??? 利用邮局发信也应该是静态的方法。 但是从变动的方面看,联邦快递和中国邮局又应该是不同的对象啊,他们的处理方法不一定相同啊, 因此他们的接口就是 这个模块的功能 interface{ send(); } 再比如log,一般来说 我们只用它log一些信息就够了,静态的方法就行了 可是java 出现了这么多实现,因此才有了commons-logging的 private static Log log = LogFactory.getLog(this.class); log.error... |
|
返回顶楼 | |
发表时间:2004-04-02
综合回答上面两位的意见:
jeffrey_he的说法我是同意的。 如果你在系统里有一个“邮局”对象,那么,这个邮局对象就应该可以接受一个sendmail的请求,他还可以接受其他的请求,比如领包裹,查询挂号信等等。这意味着一个对象的很多内部状态,需要它自行管理。 但是,如果你只是想发信,也不考虑它的内部状态,那么这种事情,就应该只用一个功能函数来解决。这个时候,硬要把一个功能函数,看成一个对象,是有问题的。 sim114的说法和jeffrey_he的说法可以统一起来考虑,同样的发邮件,之后当这个功能足够复杂时,而且存在内部状态时,我们才需要把看成一个对象。 你举的log的例子,和我要说的是一个意思,如果只是一个写文件的操作,那么封装成对象,只会导致混淆。 |
|
返回顶楼 | |
发表时间:2004-04-02
对象就是对象,简单的也是对象。
|
|
返回顶楼 | |
发表时间:2004-04-02
jeffrey_he 写道 对象就是对象,简单的也是对象。
ADT,Object Base和Object Oriented完全是三个不同的概念,虽然他们可能采用相同的语法。 |
|
返回顶楼 | |
发表时间:2004-04-03
1、我们知道一个对象,都可以包含属性和方法,一般来说,属性都不应该是public的,除非这个对象的实质是一个静态的函数库(如果从编程规范性考虑,即使是一个静态函数库的属性,也最好不要公开)。方法也主要可以分为两类,一类是对内的,这样的函数只是出于“结构化编程的优化考虑”才需要的。另一类是对外的,这样的方法,我们可以称之为“这个对象对外公开的接口”,也可以说,是这个对象能够接受的“请求”。
2、一个方法如果不改变其所属对象的内部属性,而且这个方法的执行效果也与对象的内部属性无关。那么这个方法的效果实际上就只取决于调用者传入的参数。也就是说,这个方法在逻辑上其实不应该属于这个对象。 举例说明: class PostMan { //...... public postMail(String MailAddress,String MailBody);{ //TODO System.out.println("Send mail "+MailBody+" to:"+MailAddress);; } //...... } 这个发送邮件的方法,其实与PostMan完全无关,所以从逻辑上来说,这个方法应该不属于PostMan这个对象。 class PostMan { //...... private int PostCount; public postMail(String MailAddress,String MailBody);{ //TODO PostCount++; System.out.println("Send mail "+MailBody+" to:"+MailAddress);; } //...... } 如果这个方法还会记录这个邮递员的发送邮件数量,那么这个方法就是属于PostMan这个对象的。 3、一个系统的分析过程,将会得到很多的名词和动词。我们可以将名词简单的分层。 引用 真实 名词 世界 | | | | | 分析方向 | | V V 计算机 名词 世界 这个分层的基本含义是,从真实世界的名词开始提取,而不是反过来。而且不要将动名词,后者说仅仅将做这个动作的某物归入对象。在这个过程中,不要试图将每一个动作都塞入对象,也不要为了一个动词有一个归属,而生造一个对象。通过上面的分析,无法归类的动词,就应该分门别类,以模块,而非对象的思路,进行实现。 4、对于一个对象对外提供的方法,从概念上来说,应该都属于“请求”,而非“命令”。只有对于特定功能模块的调用,才应该称之为“命令”。一个系统也因此可以分为:代表真实世界运作方式的对象层,和以各种方式直接与计算机联系的模块层和系统平台层。 5、如果一个功能模块相当复杂,也可以进一步分析,找出其中的对象层与模块层。或者以面向对象思路实现某种功能,但是这并不代表着“真实世界含义上的对象”。而只是一种“思路”。 6、进一步分析一个对象内部的方法,可以区分出仅仅从逻辑上属于这个对象的方法,与并且在含义上属于这个对象的方法。方法是否逻辑上属于一个对象,可以按照上面的标准来衡量。而含义上是否属于一个对象,则是从真实世界的情况出发分析的。 7、所有在含义上属于一个对象的方法,只需要考虑其在一个对象继承体系上所应处的位置。而仅仅在逻辑上属于一个对象的方法,在AOP的思路出现之前,只能在不同的(甚至毫无关联的)类中写下重复或者类似的代码。这样的写法,从面向对象的角度来看,毫无问题,但是确实相当浪费,而且不够“优雅”。因此,我们可以说,AOP是面向过程思想,在OOP占主导地位的时代,进行的一次反击。 |
|
返回顶楼 | |