浏览 9479 次
锁定老帖子 主题:再谈面向对象的思维方法
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-03-25
Robbin的发mail的例子很好,我们就还是拿它来讨论吧。 引用 举个例子,要发广告邮件,广告邮件列表存在数据库里面。 那么实现的过程肯定是这样的: 1. 连接数据库,取邮件地址列表。 2. 遍历邮件列表,设定新邮件(Address, title, body) 3. 调用本机的qmail的sendmail命令发送邮件。 作为一个面向对象的程序员,在写代码之前我主要要考虑什么呢? 1. 怎么封装对象 2. 怎么降低耦合度 3. 怎么实现可重用,比如不从数据库读,而改从文件读怎么处理。再比如不用Qmail,改用Rmail怎么处理。 考虑了以上的问题后,我会这么实现: 1. 首先定义一个Mail DataObject public class MailDTO { private String strAddress; private String strTitle; private String strBody; public MailDTO(); {super();;} public MailDTO(String strAddress, String strName, String strType); { setAddress(strAddress);; setName(strName);; setType(strType);; } public String getAddress(); {return this.strAddress;} public void setAddress(String strAddress); { this.strAddress = strAddress;} public String getTitle(); {return this.strTitle;} public void setTitle(String strTitle); { this.strTitle = strTitle;} public String getBody(); {return this.strBody);;} public void setBody(String strBody); { this.strBody); = strBody);;} } 2. 定义ListAddress接口 public interface ListAddress { public Iterator getListAddress(); } 3. 定义ListAddress接口的实现DbListAddress public class DbListAddress implements ListAddress { public Iterator getListAddress(); { //blablabla } } 以后你可以加FileListAddress, 只要implements ListAddress 4. 定义SendJunk接口 public interface SendJunk { public void sendJunk();; } 5. 定义JunkData类 public class JunkData { protected MailDTO mdto; public void setMailDTO(MailDTO mdto); { this.mdto = mdto; } } 6. 定义Qmail的SendJunk的实现 public class QmailSendJunk extends JunkData implements SendJunk { public void sendJunk(); { //blablabla } } 这里要注意的是它 extends JunkData, implements SendJunk,所以用的时候得这么写: SendJunk sj = new QmailSendJunk();; sj.setMailDTO(mdto);; sj.sendJunk();; 同样,以后你可以加Rmail, Smail, Tmail......只要extends JunkData implements SendJunk 7. 控制程序 SendJunk sj = new QmailSendJunk();; ListAddress la = new DbListAddress();; MailDTO mdto = new MailDTO();; mdto.setTitle("good news");; mdto.setBody("blablabla");; Iterator it = la.getListAddress();; while (it.hasNext();); { String strAddress = (String);it.next();; mdto.setAddress(strAddress);; sj.setMailDTO(mdto);; sj.sendJunk();; } 这里要说的有两点: 1. 以后要改写的就是添加ListAddress和SendJunk这两个接口的实现,然后把控制程序的第1,2行换成相应的class。 2. 一个小Tip,尽量避免在while里面用new,否则如果你的iterator很长,系统消耗会很大。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-03-25
总结的好, 支持。
|
|
返回顶楼 | |
发表时间:2004-03-25
bruce 写道 总结的好, 支持。
总结的不好,不支持 |
|
返回顶楼 | |
发表时间:2004-03-26
我写那篇文章的时候是从入门的角度来考虑的,所以没有想那么深入和细致,谢谢你的总结,以后改写这篇文章的时候就可以加入这部分内容,并且注明引用自xanada。
不过我想在你的总结基础上再加点东西,也许就更完美些: SendJunk sj = new QmailSendJunk();; ListAddress la = new DbListAddress();; 考虑到这两行可以继续修改。之所以抽象出接口是了为了重用,不过此时抽换了接口实现类仍然要修改代码,应该写一个工厂类用来获得接口实现类,而不是直接硬编码。 SendJunk sj = JunkFactory.getSendJunk();; ListAddress la = ListAddress.getListAddress();; 然后在工厂类方法里面根据某些条件,例如类搜索的顺序,或者读配置文件,或者读命令行传入的参数来决定load哪种接口实现类。这样抽换接口实现类,就不必改代码了。 |
|
返回顶楼 | |
发表时间:2004-03-26
在下初来,很喜欢这里的气氛。希望Robbin你的论坛能够越办越好,牛人越聚越多。。。
|
|
返回顶楼 | |
发表时间:2004-03-27
Gamble ,Gamble never changes
|
|
返回顶楼 | |
发表时间:2004-03-27
public class QmailSendJunk extends JunkData implements SendJunk { public void sendJunk(); { //blablabla } } 谈谈我的看法, 首先extends代表一种 is a 的关系, 尽管此处可以这样使用, 但如果说QmailSendJunk is a JunkData, 看起来QmailSendJunk中就一个sendJunk()方法, 所以这样的is a 关系不太合适。 我觉得此处可以使用bridge模式, 把JunkData看做bridge模式的抽象部分(叫abstraction), 把动作sendJunk()看做bridge模式的implementation部分。 随便举一个例子, 不一定贴切, 假设 JunkData 就是一种Data, 它有XML格式和HTML格式。所以abstraction这边的父类为Data, 它的两个子类为XMLData, HTMLData, implementation这边的父类为processMail, 它有两个子类有Qmail和Sendmail两种方式, 所以可以有四种组合: XMLData+Qmail, XMLData+Sendmail, HTMLData+Qmail, HTMLData+Sendmail. 我们可以通过了客户程序处任意指定这四种方式中的几种。 或者, 你可不可以直接用组合的方式,这样就不会是parent-chid的tightly coupling relationship了, 象这样: public class QmailSendJunk JunkData implements SendJunk { private JunkData myJunkData = new JunkData();; public QmailSendJunk(MailDTO mdto);{ myJunkData.setMailDTO(mdto);; } public void sendJunk(); { //blablabla } } 在重构中, 如果想保证接口不变,可以考虑proxy和decorator模式,其实它们也是在内部应用组合方式,接口要改变但以前的类内部不改动,可以考虑adaptor模式,它也是组合方式的应用。如果以前类的结构已经定下来,不好再改,但需要扩充类的功能,可以考虑使用visitor模式。这个模式是我最头痛的模式:(, 不过是越来越清楚了。 Robbin,说到的应是一种简单工厂模式, 通过传参数来决定不同类的实例化, 但如果可能的话, 我更愿意把产品抽象出来, 做一种工厂模式或抽象工厂模式, 好处就是代码以后的改动要比简单工厂模式少,这样所有的类的实例化推迟到客户端,是一种真正的面象对象的编程, 当然不好的就是比简单工厂麻烦。 |
|
返回顶楼 | |
发表时间:2004-04-02
为啥要一个JunkData类呢?而且还让QmailSendJunk 去继承它?
这样子让程序变得难以理解了。 |
|
返回顶楼 | |