关闭

java设计模式——观察者模式(Observer Pattern)

标签: 观察者模式Observer Patternjava设计模式设计模式
117人阅读 评论(0) 收藏 举报
分类:
概述:
       观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

定义:
       定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

结构:
  • Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
  • ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
  • Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
  • ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的addObserver()方法将自己添加到目标类的集合中或通过deleteObserver()方法将自己从目标类的集合中删除。

UML图:


场景:在平时生活中有很多场景都有观察者模式的影子,比如商城宣传、街头艺人、马路交通信号灯等等,这里就举一个过马路的例子,一般十字路口都会有红绿灯,不管行人还是车辆都要根据交通信号灯的信号来确定什么时候过马路,红灯停、绿灯行,这是小学都学过的交通规则了,当然不守交通规则的sb不算。这里的交通信号灯就相当于目标(被观察者),行人或者司机属于观察者。

代码分析:
/**
 * Created by **
 * 目标抽象类
 */
public abstract class Subject {
    private ArrayList<Observer> observers new ArrayList<Observer>();

    /**
     * 增加观察者
     @param observer
     */
    public void addObserver(Observer observer){
        observers.add(observer);
    }

    /**
     * 移除观察者
     @param observer
     */
    public void deleteObserver(Observer observer){
        observers.remove(observer);
    }

    /**
     * 向观察者发出通知
     @param string
     */
    public void notifyObservers(String string){
        for (Observer observer : observers) {
            observer.update(string);
        }
    }
}

/**
 * Created by **
 * 交通信号灯:具体目标
 */
public class TrafficLight extends Subject {
    /**
     * 显示红灯
     */
    public void showRedLight(){
        LogFactory.log("红灯亮了");
        super.notifyObservers("red");
    }
    /**
     * 显示绿灯
     */
    public void showGreenLight(){
        LogFactory.log("绿灯亮了");
        super.notifyObservers("green");
    }
}

/**
 * Created by **
 * 观察者接口
 */
public interface Observer {
    // 更新操作
    public void update(String string);
}

/**
 * Created by **
 * 司机:观察者
 */
public class Driver implements Observer {
    @Override
    public void update(String string) {
        LogFactory.log("E lights :"+string);
        if ("red".equals(string)){
            stop();
        }else if ("green".equals(string)){
            travel();
        }else {
            LogFactory.log("交通信号灯坏了?...");
        }
    }

    private void travel(){
        LogFactory.log("绿灯亮了,可以过马路了");
    }

    private void stop(){
        LogFactory.log("红灯亮了,停止前行");
    }
}

客户端调用:
TrafficLight trafficLight = new TrafficLight();

Driver driver = new Driver();

trafficLight.addObserver(driver);

trafficLight.showGreenLight();

try {
    Thread.sleep(2000);
    trafficLight.showRedLight();
catch (InterruptedException e) {
    e.printStackTrace();
}

log输出:
08-19 15:14:41.842 2648-2648/? D/test: 绿灯亮了
08-19 15:14:41.842 2648-2648/? D/test: E lights :green
08-19 15:14:41.842 2648-2648/? D/test: 绿灯亮了,可以过马路了
08-19 15:14:43.842 2648-2648/? D/test: 红灯亮了
08-19 15:14:43.842 2648-2648/? D/test: E lights :red
08-19 15:14:43.842 2648-2648/? D/test: 红灯亮了,停止前行

      上述例子,我只是添加了一个观察者,如果要添加多个观察者直接调用addObserver方法即可,另外观察者模式在java语言中的地位非常重要所以jdk里边提供了相关的接口来支持该模式。

JDK提供的Observable类及Observer接口:
  • Observer接口:相当于观察者接口。该接口只声明一个方法:update(Observable observable, Object data)。
  • Observable类:相当于目标抽象类(Subject)。该抽象类中有多个方法:
          
下面将上述代码做一下修改,将具体的目标类继承Observable,将具体的观察者类实现Observer接口:
/**
 * Created by **
 * 交通信号灯:具体目标
 */
public class TrafficLight extends Observable {
    /**
     * 显示红灯
     */
    public void showRedLight(){
        LogFactory.log("红灯亮了");
        super.setChanged();
        super.notifyObservers("red");
    }
    /**
     * 显示绿灯
     */
    public void showGreenLight(){
        LogFactory.log("绿灯亮了");
        super.setChanged();
        super.notifyObservers("green");
    }
}

/**
 * Created by **
 * 司机:观察者
 */
public class Driver implements Observer {
    /*@Override
    public void update(String string) {
        LogFactory.log("E lights :"+string);
        if ("red".equals(string)){
            stop();
        }else if ("green".equals(string)){
            travel();
        }else {
            LogFactory.log("交通信号灯坏了?...");
        }
    }*/
    @Override
    public void update(Observable observable, Object data) {
        LogFactory.log("E lights :"+data);
        if ("red".equals(data.toString())){
            stop();
        }else if ("green".equals(data.toString())){
            travel();
        }else {
            LogFactory.log("交通信号灯坏了?...");
        }
    }
    private void travel(){
        LogFactory.log("绿灯亮了,可以过马路了");
    }

    private void stop(){
        LogFactory.log("红灯亮了,停止前行");
    }

}

客户端的代码不需要更改,最后log输出都是一样一样的,你们可以自己验证一下。

优点:
  • 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
  • 观察者模式在观察目标和观察者之间建立一个抽象的耦合。
  • 观察者模式支持广播通信。
  • 观察者模式符合“开闭原则”的要求。

缺点:
  • 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

适用环境:
  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

扩展:
      MVC模式是一种架构模式,它包含三个角色:模型(Model),视图(View)和控制器(Controller)。观察者模式可以用来实现MVC模式,观察者模式中的观察目标就是MVC模式中的模型(Model),而观察者就是MVC中的视图(View),控制器(Controller)充当两者之间的中介者(Mediator)。当模型层的数据发生改变时,视图层将自动改变其显示内容。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9954次
    • 积分:526
    • 等级:
    • 排名:千里之外
    • 原创:45篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    最新评论