lyl3333489

2007年7月10日

骑警

posted @ 2007-07-20 17:28 AAAAA 阅读(288) | 评论 (1)编辑 收藏

观察者模式

    常听说这么一句话(大意是这样):不必可以去套用设计模式,如果按照面向对象的基本原则编程,自然是优雅的设计,即使没有刻意使用模式,设计也会近乎于模式。开始感觉有一点玄,但在看了《C#设计模式纵横谈》视频后,觉得有所收获。下面,就参考视频的内容,尝试着写这么一个过程:根据面向对象的一般原则对设计进行重构,逐渐演化出观察者模式。
涉及的面向对象设计原则:单一职责原则、封装变化、面向接口编程、依赖倒置原则、开闭原则。

1.发布订阅模型:



         
               
假如有需求如下:

银行需要把帐户的如汇款、转账或取款等操作通知用户,途径包括手机短信、 email等。如图所式。

自然地,我们可以这样做:

public class ATM
 {
     BankAccount bankAccount;
     
     
public void process()
     {
          
//bankAccount...
         this.sendEmail(userEmail);
         
this.sendPhone(phoneNumber);
     }
 
     
private void sendEmail(String userEmail)
     {
         
//
     }

    
private void sendMobile(String phoneNumber)
     {
         
//
     }
 }

ATM机的 process()方法在处理完业务逻辑后,由email和phone通知用户。

2.初步重构

好像有bad smells,恩,根据单一职责原则。新增Email类和Phone类,并把相关业务逻辑改到BankAccount类完成。于是我们的代码可以这样:


public class ATM
{
    BankAccount bankAccount;
    
    
    
public void process()
    {
          
//
          bankAccount.withDraw();
    }
 
 }

public class BankAccount 
{
    Email email;
    Mobile mobile;

    
public void withDraw()
    {
         
//
         email.sendEmail(userEmail);
         mobile.sendMobile(phoneNumber);
    }
}

public class Email
{
    
public void sendEmail(String userEmail)
    {
    }
}

public class Mobile
{
    
public void sendMobile(String phoneNumber)
    {
    }
}

下面是代码的UML图:




3.拥抱变化

这个解决方案有问题吗?可能没有问题。它实现了我们的需求:在帐户有操作变动的时候,通知Email和Mobile去发送信息给用户。但这样设计就足够了吗?可能足够了,可能还不够。
考虑如下两种情况:
1.在很长一段时间里,订阅方式很稳定,比如系统只通过邮件和手机短信进行信息订阅,那么这个实现没有太大问题;
2.在近一两年或更短的时间,更多的订阅方式将会源源不断地被加进来:比如可以登录官方网站等等,那这个实现就有问题:再看一下我们的UML图,类BankAccount依赖于Email和Mobile类!就是说,如果需要添加新的订阅方式ATM类的process()方法势必要重新设计!

于是我们的BankAccount类不得不变成:

public class  BankAccount
{
    Email email;
    Mobile mobile;
    Web web;

    
public void withDraw()
    {
          
//
         email.sendEmail(userEmail);
         mobile.sendMobile(phoneNumber);
         web.sendWeb(webSite);
    }
 
 }

如果还有另一种方式,那么process()方法就又会需要加入:otherSubscribe.send...();等方法,另外如果订阅类的接口(这里指sendEmail等方法)发生变化,BankAccount的withDraw()方法也必须有相应的变化!这当然是种灾难。我们必须改变这种情况。
先解决遗留问题:第一种情况:订阅方式相对稳定的情况下呢?不改动会产生灾难吗?
个人认为:不会。比如某个系统信息只通过手机短信订阅,那就没有必要太在意这个问题。考虑周全一点不好吗,如果将来有类似需求呢?小心过度设计!为了将来可能出现需求而进行的预先设计并不太好。有需求,才有设计。

现在来看解决之道:

运用面向对象的思想,抽象出问题所在。BankAccount类依赖于 Email类和Mobile类,而Email和Mobile是具体的类,ATM依赖于具体的类了,而且还不止一个!回忆一下依赖倒置原则:具体应该依赖于抽象,底层模式应该依赖于高层模式那怎么实现依赖倒置原则呢?面向对象编程中有一条总的原则:封装变化。如何实现封装变化?需要我们这样:面向接口编程

回顾一下:我们在设计中实现类依赖了具体的类,违反了依赖倒置原则。为了遵循依赖倒置原则,我们采用面向接口编程的方法,从而实现了面向对象的一条总的原则:封装变化。


看代码:

public interface AccountObserver
{
    
public void upDate(UserAccount userAccount);
}

public class Email implements AccountObserver
{
    
public void upDate(UserAccount userAccount)
    {
    }
}

public class Mobile
{
    
public void upDate(UserAccount userAccount)
    {
    }
}

public class BankAccount 
{
    List 
<AccountObserver> observer = new ArrayList<AccountObserver>;

    
public void withDraw()
    {
         
//
         for (AccountObserver ao : observer)
         {
            ao.upDate(userAccount)
          }
    }
    
    
public void addOberver(AccountObserver accountObserver)
    {
          observer.add(accountObserver);
     }
}

UML图:



现在,BankAccount依赖于interface AccountObserver。Email和Mobile实现AccountObserver接口。通过遵循面向接口编程遵循了依赖倒置原则

4.开闭原则

终于修改好了,我们解决了订阅者变化的问题。但如果发布者也倾向于变化呢?这就牵涉到面向对象里的另一个原则:开闭原则即:对扩展开放,对修改关闭。具体怎么做呢?通过抽象类,从抽象类继承具体类。
看最终的代码(只写几个关键的方法,全貌可看最后的UML图):

订阅:

public interface AccountObserver
{
    
public void upDate(UserAccount userAccount);
}

public class Email implements AccountObserver
{
    
public void upDate(UserAccount userAccount)
    {
    }
}

public class Mobile implements AccountObserver
{
    
public void upDate(UserAccount userAccount)
    {
    }
}


发布:



public abstract class Subject
{
     List 
<AccountObserver> observer = new ArrayList<AccountObserver>;

    
protected void withDraw()
    {
         
//
         notify();
         
    }
    
    
protected void notify(UserAccount userAccount)
    {
         
for (AccountObserver ao : observer)
         {
            ao.upDate(userAccount)
          }
     }
    
    
protected void addOberver(AccountObserver accountObserver)
    {
          observer.add(accountObserver);
     }

      
protected void deleteOberver(AccountObserver accountObserver)
    {
          observer.remove(accountObserver);
     }

}

public class BankAccount extends Subject
{
    
public void withDraw()
    {
         
//
         for (AccountObserver ao : observer)
         {
            ao.upDate(userAccount)
          }
    }
    
}



看UML图:




5.观察者模式概况




这就是观察者模式了,对比一下官方的UML图,是不是一目了然了呢?
稍作说明(这里的依赖都是指广义的依赖):
1.被观察者ConcreteSubject继承自Subject抽象类;
2.Subject抽象类依赖于观察者Observer抽象接口;
3.观察者ConcreteObserver实现Observer 接口;
4.观察者ConcreteObserver间接依赖于ConcreteSubject类。
如果要增加具体的观察者,只要再实现Obsever接口即可,而被观察方不需要做任何修改。而如果需要修改被观察者,只要从Subject抽象类继承即可。

posted @ 2007-07-10 10:36 AAAAA 阅读(317) | 评论 (0)编辑 收藏

收集的网址

http://www.linuxfans.org   
http://www.otasuke.ne.jp/modules/xwords/index.php   
http://jp.hjenglish.com/papers.aspx   
www.21cnhr.gov.cn   
http://www.ytv.co.jp/conan/   
http://www13.tianya.cn/new/Publicforum/Content.asp?idWriter=3915484&Key=228823315&strItem=no04&idArticle=483393&flag=1   
http://piano.stedu.net/   
http://www.nhk.or.jp/           <<NHK>>           http://www.nhk.or.jp/r-news/   
http://www.intel.com/software/cn/mcwebcast/#slide=1    intel class   
http://www.yangmi.net/ky/Print.asp?ArticleID=13801   !!!   
http://bbs.i18.cn/index.asp     中国零售网   
http://www.fortunespace.net/forum/    中国財富論壇   
http://www.yesky.com/SoftChannel/72357786515668992/20040129/1764106.shtml  求和   
http://www.yesky.com/SoftChannel/72348968914255872/20050126/1905902.shtml Excel ?用   
http://www.yesky.com/soft/office/excel-news/his/his_4.shtml  Excel   
http://www.4399.net/flash/1602_2.htm?800 golden   
http://edu.itbulo.com/200511/58025.htm        ITbulo   
http://202.103.49.240/jsjzs/excel/excelyy.htm    Excel 排序   
http://192.168.1.23/use_wf/Dep_App     WF  WF  WF  WF   
http://www.yodian.com   有点   
http://www.dlsp.com.cn   DLSP   
http://64.233.179.104/search?q=cache:QqZYnKlqqEwJ:members.at.infoseek.co.jp/skillup/yougo/yougo6.htm+EOB%E3%80%80Electronic&hl=ja&gl=jp&ct=clnk&cd=1&lr=lang_ja   
http://www.codesky.net   CODE   
    
http://www1.tianya.cn/new/TechForum/Content.asp?idWriter=3915484&Key=840161655&idItem=81&idArticle=251915   
http://www.chinacs.net/archives/8/2004/12/12/3188.html       C#   
http://music.whnews.cn/playgame/flashshow.php?flashid=895      SC   
http://www.tianya.cn/new/TechForum/Content.asp?idWriter=3915484&Key=481775086&idItem=81&idArticle=562447   
http://192.168.1.211/TRIAL/upload/jinji/study/access/    ACCESS   
http://www.wswire.com/      huaerjie dianxun   
http://infoseek.amikai.com/amitext/indexUTF8.jsp   
http://www.51windows.net/pages/ado/?url=/pages/ado/mdmthaddnew.htm      ADO    ADO 
http://www.51windows.net/
  
http://www.codechina.net/resource/sort.php/621/4       Access VBA  Code   
http://jakarta.apche.org        struts   
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/csref/html/vcoricsharptutorials.asp       MSDN c#   
http://www.daliancity.com.cn/job/index.php     DLZX 
http://www.cjsdu.com/   DuiRiLunTan


http://www.mutouyu.com/translation/ 木頭魚翻訳

http://www6.tianya.cn/new/techforum/Content.asp?idWriter=3915484&Key=700727019&idItem=81&idArticle=574220

http://localhost:8080/solves4/pages/CM/AAA/CMAAA001R.jsp

http://www.tianya.cn/new/techforum/Content.asp?idWriter=3915484&Key=292720848&idItem=81&idArticle=568508

http://www1.tianya.cn/new/techforum/Content.asp?idWriter=3915484&Key=189209006&idItem=81&idArticle=573983

http://www2.tianya.cn/new/techforum/Content.asp?idWriter=3915484&Key=677920263&idItem=81&idArticle=573828
 hua xian chuang guan

http://www.4399.net/flash/4362_4.htm?1024
 pao tai TD

http://www.excite.co.jp/world/chinese/
 onlineTranslate

http://www.4399.net/flash/457_1.htm?800
 qiJi

http://www.javaeye.com/
 
http://www.andykhan.com/jexcelapi/
 JXL(JAVA Excel API)

http://www.uml.org.cn/sjms/200703274.asp
 設計モード

http://www.okajax.com/
 Ajax 中国

http://www.nicenic.com/domain/
 域名


域名最长的网站
http://www.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk/
http://www.111111111111111111111111111111111111111111111111111111111111.com/
http://3.141592653589793238462643383279502884197169399375105820974944592.com/
http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/

几个不错的JAVA学习网站
http://www.csdn.net(社区、文档、bolg、知识库)
http://www.hibernate.org.cn
http://www.blogjava.net
http://www.jdon.com
http://www.javafan.net
http://www.open-open.com
http://dev2dev.bea.com.cn/
http://www.javaresearch.org/
http://www.codechina.net/resource/
http://gceclub.sun.com.cn
http://www.javaeye.com
http://WWW.chinaitlab.com  中国IT試験室

您的Blog地址是:http://www.blogjava.net/lyl3333489/

 

posted @ 2007-07-10 09:05 AAAAA 阅读(242) | 评论 (0)编辑 收藏

<2007年7月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(1)

随笔档案

相册

搜索

最新评论

阅读排行榜

评论排行榜