`
uhlan
  • 浏览: 2288 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Refactoring To Patterns: 观察者模式

阅读更多
    常听说这么一句话(大意是这样):不必可以去套用设计模式,如果按照面向对象的基本原则编程,自然是优雅的设计,即使没有刻意使用模式,设计也会近乎于模 式。开始感觉有一点玄,但在看了《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抽 象类继承即可。
分享到:
评论

相关推荐

    Refactoring To Patterns《重构与模式》英文版

    - 例如,观察者模式可以通过事件监听器或回调函数等方式实现,每种方式都有其优缺点。 - 了解这些差异有助于开发者根据项目的具体需求选择最适合的方案。 4. **低级别重构与高级别模式的结合** - 重构不仅仅是...

    Refactoring To Patterns

    《Refactoring To Patterns》这本书由Joshua Kerievsky编写,是关于重构技术与设计模式相结合的重要参考资料。本书深入探讨了如何通过重构来实现更好的软件设计,特别是在引入设计模式的过程中,旨在帮助读者理解和...

    Refactoring to Patterns

    设计模式包括工厂模式、单例模式、观察者模式、策略模式等,每种模式都有其特定的应用场景和优势。 在《重构到设计模式》一书中,作者详细介绍了如何识别代码中的问题模式,并逐步引导读者将这些问题模式转换为已知...

    重构与模式(Refactoring To Patterns)

    《重构与模式(Refactoring To Patterns)》这本书深入探讨了软件开发中的一个重要主题:如何将现有的代码结构逐步改进,使其更符合设计模式,从而提升软件的可读性、可维护性和扩展性。这本书是面向已经有一定编程...

    重构与模式 Addison Wesley Refactoring To Patterns

    《重构与模式》讨论了如何在重构过程中识别和引入设计模式,如工厂模式、单例模式、观察者模式等,这些模式有助于我们构建更灵活、可扩展的软件架构。 书中的核心观点是,重构和模式并不是孤立的概念,而是相辅相成...

    Refactoring to patterns - Joshua Kerievsky

    《Refactoring to Patterns》是Joshua Kerievsky所著的一本专业书籍,主要内容涉及软件设计中的重构和模式应用。本书详细介绍了通过一系列低级重构来安全地将设计向特定模式实现移动、靠近或远离的方法。Kerievsky以...

    refactoring to patterns

    《重构至设计模式:深化代码结构的理解与应用》 重构至设计模式,是软件开发...以上只是书中所涵盖的一部分知识点,更多深入的内容,如装饰器模式、观察者模式等,都有详细的讲解和示例,值得读者进一步探索和学习。

    (行为型模式) Observer 观察者模式

    ### (行为型模式) Observer 观察者模式 #### 概述 观察者模式是一种行为设计模式,它定义了一种一对多的关系,让多个观察对象同时监听某一个主题对象。当主题对象发生变化时,所有观察者对象都会收到通知并进行...

    重构与模式(Refactoring.to.Patterns)(中英版)

    《重构与模式(Refactoring.to.Patterns)》是一本深入探讨软件开发中重构与设计模式融合的权威著作。这本书的中英双语版为读者提供了更广泛的阅读选择,无论你是初学者还是经验丰富的开发者,都能从中获益匪浅。...

    xUnit Test Patterns Refactoring Test

    以上这些测试模式和重构技巧都是《xUnit Test Patterns: Refactoring Test》书中所涵盖的核心内容。通过学习和应用这些模式,开发者能够编写出更加健壮、可维护的测试代码,从而提高软件的整体质量。

    refactoring-improving the design of existing code.pdf

    书中融入了一些设计原则,如单一职责原则、开闭原则等,以及一些设计模式,如工厂模式、观察者模式等,这些都是在重构中考虑的高级设计元素。 5. **步骤与技巧**:书中详细描述了如何逐步进行重构,从识别问题到...

    refactoring-to-patterns-notes:重构-向范式前进(重构为模式)的学习笔记

    例如,工厂模式用于创建对象,观察者模式用于实现对象间的发布-订阅机制,单例模式确保一个类只有一个实例。书中通过实际案例展示了如何在重构过程中识别并应用这些模式,使代码更加符合面向对象设计原则,如单一...

    设计模式.rar

    在《Refactoring To Patterns》这本书中,作者深入探讨了如何通过重构代码来引入和应用设计模式,提升软件的可读性和可维护性。以下是关于设计模式的一些核心知识点: 1. **设计模式的定义**:设计模式是针对特定...

    [电子书] 重构与模式

    《Refactoring to Patterns》一书的核心观点是将重构视为向设计模式演进的过程。作者详细介绍了如何通过重构步骤将现有代码结构转换为设计模式。例如,通过重构可以将一个简单的类转换为工厂模式,或者将一组类之间...

    侯捷-Design Patterns 設計範式

    - Observer 模式(观察者模式):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 - State 模式(状态模式):允许一个对象在其内部状态改变时改变它的...

    从重构到模式(英文版)

    《从重构到模式》是Addison Wesley出版社出版的一本关于软件开发进阶的书籍,英文原版名为"Refactoring To Patterns"。这本书的核心主题是探讨如何通过重构代码来逐步引入设计模式,提升软件的可读性、可维护性和可...

    Software-Design-Patterns-Refactoring-Exercise

    设计模式分为三大类:创建型模式(如单例模式、工厂模式)、结构型模式(如适配器模式、装饰器模式)和行为型模式(如观察者模式、策略模式)。这些模式不仅提供了标准的解决方案,还促进了团队间的沟通和代码的理解...

    23种设计模式 - 架构设计 - PPT

    - **观察者模式(Observer)**:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 - **命令模式(Command)**:将一个请求封装为一个对象,从而使用户可用...

    二十三种设计模式【PDF版】

    设计模式之 Observer(观察者) 介绍如何使用 Java API 提供的现成 Observer 设计模式之 Iterator(迭代器) 这个模式已经被整合入Java的Collection.在大多数场合下无需自己制造一个Iterator,只要将对象装入...

Global site tag (gtag.js) - Google Analytics