设计模式之观察者模式(Java)

  设计模式(Design pattern)是什么?它是一套由四人组(The Gang of Four, [1]的作者)总结出来的软件设计框架。其目的是为了提高代码的可重用性,增强系统的可维护性和代码的易读性。在四人组的《Design Patterns》一书中提到了23中最常用的设计模式,大致可以分为三大类:
  1. 创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式;
  2. 结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥连接模式、组合模式、享元模式;
  3. 行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

  关于上面23中设计模式的大概介绍可以参考博客[2]。

  从上面的分类可以看出观察者模式是一种对象的行为型模式。它也被称之为发布-订阅(Publish-Subscribe)模式、模型视图(Model-View)模式或源-监听器(Source-Listener)模式[3]。通俗的说,观察者模式涉及到(至少)两个对象。其一是观察者,其二是被观察者。例如在一个RSS订阅系统中,发布方充当被观察者角色,而订阅方则充当了观察者角色。一般来说,观察者与被观察者是多对一的关系。即多个监听器可以同时监听某一主题对象。当主题对象状态发生改变时,监听器对象也会自动的更新自身状态。
 
   这篇博客主要是从一个实际的例子出发,来简单的说明Java(Android)、Objective-C(iOS)、C#(Windows Phone)三种面向对象编程语言对观察者模式的实现。
 

观察者模型实例之烧开水

  从一个烧开水的例子出发。现在我们有个热水器,我们用它来烧开水。在烧水的过程中,显示器和扬声器都一直监视水温。显示器将水温显示在显示屏上。另外,当水温超过90度时,扬声器开始发出警告,提示水快烧开。

Java实现

  Java对观察者类的支持,主要体现在Observable类和Observer接口。

1. java.util.Observable类 = 被观察者

Observable类的主要方法:

public class Observable {
    void setChanged(); //设置被观察者的状态已经被改变
    void clearChanged(); //清除被观察者状态的改变,此时再调用hasChanged()将返回false
    void addObserver(Observer observer);
    int countObservers();
    void deleteObserver(Observer observer);
    void deleteObservers();
    boolean hasChanged();
    void notifyObservers();
    void notifyObservers(Object arg); // 参数一般设定为被改变的属性
}

热水器类继承自Observerable类,作为一种具体的被监控对象:

public class Heater extends Observable {
    private int temperature;

    // get方法,返回水温
    public int getTemperature(){
        return temperature;
    }

    // set方法,设置水温
    public void setTemperature(int temperature){
        this.temperature = temperature;
    }

    // boilWater方法,烧水
    public void boilWater(){
        for(int i = 30; i <= 100; i++){
            this.setTemperature(i);
            this.setChanged();
            this.notifyObservers(this.getTemperature());
            this.clearChanged();
        }
    }
}
2. java.util.Observer接口 = 观察者

  Observer接口只有一个抽象方法需要被具体的观察者实现。

public interface Observer{
    void update(Observable observable, Object arg); //这里的arg即Obserbale类里的notifyObservers(Object arg)传过来的参数
}

  Note:当被观察者调用nofityObservers(*)方法时,会根据被观察者的hasChanged()方法来判断它的状态是否被改变。如果改变,则观察者调用update方法。否则不调用(即不更新)。

  显示器和扬声器作为具体的热水器水温监视者,都需要实现Observer接口。对于显示器,它的update方法作用就是更新显示的水温。对扬声器,它的update方法则是在水温超过90度时发出警告。具体代码如下:

// 显示器
public class Displayer implements Observer {
    public void update(Observable observable, Object arg){
        display((int)arg);
    }
  
    public void display(int temperature){
        System.out.println("Current Temperature is: " + temperature  + " degree.");
    }
}

// 扬声器
public class Alertor implements Observer {
    public void update(Observable observable, Object arg){
        int temperature = (int) arg;
        if(temperature > 90){  
            alarm();
        }
    }

    public void alarm(){
        System.out.println("Warning: Temperature is over 90 degree!" );
    }
}
3. 测试类
public class TestObserver{
    public static void main(String[] args){
        // 生成设备
        Heater heater = new Heater();
        Displayer displayer = new Displayer();
        Alertor alertor = new Alertor();

        // 添加订阅 - 重点(!!!)
        heater.addObserver(display);
        heater.addObserver(alertor);

        // 烧水
        heater.boilWater();
    }
}
4. 将上面的3个步骤统一起来,写到一个文件中如下:文件名TestObserver.java
import java.util.Observable;
import java.util.Observer;

public class TestObserver {
    public static void main(String[] args){
        // 生成设备
        Heater heater = new Heater();
        Displayer displayer = new Displayer();
        Alertor alertor = new Alertor();

        // 添加订阅
        heater.addObserver(displayer);
        heater.addObserver(alertor);

        // 烧水
        heater.boilWater();
    }
}

class Heater extends Observable {
    private int temperature;

    // get方法,返回水温
    public int getTemperature(){
        return temperature;
    }

    // set方法,设置水温
    public void setTemperature(int temperature){
        this.temperature = temperature;
    }

    // boilWater方法,烧水
    public void boilWater(){
        for(int i = 30; i <= 100; i++){
            this.setTemperature(i);
            this.setChanged();
            this.notifyObservers(this.getTemperature());  // 只需传入监视器感兴趣的变量
            this.clearChanged();
        }
    }
}

// 显示器
class Displayer implements Observer {
    public void update(Observable observable, Object arg){
        display((int)arg);
    }
  
    public void display(int temperature){
        System.out.println("Displayer: Current Temperature is: " + temperature  + " degree.");
    }
}

// 扬声器
class Alertor implements Observer {
    public void update(Observable observable, Object arg){
        int temperature = (int) arg;
        if(temperature > 90){  
            alarm();
        }
    }

    public void alarm(){
        System.out.println("Alertor: Warning: Temperature is over 90 degree!" );
    }
}

最后的输出结果为:

Displayer: Current Temperature is:  30  degree.
Displayer: Current Temperature is:  31  degree.
Displayer: Current Temperature is:  32  degree.
...
Displayer: Current Temperature is:  90  degree.
Displayer: Current Temperature is:  91  degree.
Alertor: Warning: Temperature is over 90 degree!
Displayer: Current Temperature is:  92  degree.
Alertor: Warning: Temperature is over 90 degree!
...
Displayer: Current Temperature is:  99  degree.
Alertor: Warning: Temperature is over 90 degree!
Displayer: Current Temperature is:  100  degree.
Alertor: Warning: Temperature is over 90 degree!

总结

第一次写技术博客感觉比较费劲。原以为一个下午能把三种实现方法都写完的,结果只写完了Java部分。后续的Objective-C 和C#部分计划明天下午搞定。敬请期待。

欢迎交流和讨论^_^ ~ 如有任何问题,请发送到邮箱:fengfu0527@gmail.com

 

[1]. 《Design Patterns: Elements of Reusable Object-Oriented Software》

[2]. Java之美之设计模式,链接:http://bolg.csdn.net/zhangerqing/article/details/8194653

[3]. 《Java与模式》

 

转载于:https://www.cnblogs.com/fengfu-chris/p/3959580.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值