Fork me on Gitee

Observer模式(观察者设计模式)

Observer 设计模式?

在Observer模式中,当观察对象的状态发生变化时,会通知给观察者。Observer模式适用于根据对象状态进行相应处理的场景。

  • Observer 并非主动观察,而是被动观察,实际可以又称之为发布-订阅者模式

  • MVC
    Model、View、Controller,并且Model里面的操作不依赖于具体形式的内部模型,通常情况下:
    一个Model对应多个View,这里也是使用Observer设计模式最多的地方

  • java中观察者接口

在package java.util;下存在了Observer接口,按照二类定义模式,允许传递对象,以及附带参数

void update(Observable o, Object arg);

  • 使用注意:java.util.observer接口和java.util.observable类并不好用。理由很简单,传递给java.util.observer接口的Subject角色必须是java.util.observable类型(或者它的子类型)的。但Java只能单一继承,也就说如果Subject角色已经是某个类的子类了,那么它将无法继承java.util.observable类。(单个使用还是可以的)

理清职责

  • 实现功能:根据不同的观察者显示字符串的方式也不一样!

|名字=======》》》说明
|Observer || 表示观察者的接口
|NumberGenerator || 表示生成数值的对象的抽象类
|RandomNumberGenerator || 生成随机数的类
|Digitobserver || 表示以数字形式显示数值的类
|Graphobserver || 表示以简单的图示形式显示数值的类
|Main || 测试程序行为的类

  • Observer调用顺序问题:
    当在Observer存在多个需要通知的方法时,方法一多,容易出现混乱,所以你这里使用template设计模式将在Observer定义的使用顺序,提前安排好,
    那么子类去实现就行了。出现更改调用顺序的时机,只需要去Observer中查看。

  • 可替换性原则:

  1. 利用抽象类与接口从具体的类中抽象出方法
    2.将实例作为参数传递到类中,或者在类的字段中保存实例时,不要使用具体的类型,而是使用抽象类型接口作为参数传递。
  • 相关设计模式

◆Mediator模式
在Mediator模式中,有时会使用Observer 模式来实现Mediator角色与Colleague角色之间的通信。
就“发送状态变化通知”这一点而言,Mediator模式与Observer模式是类似的。不过,两种模式中,通知的目的和视角不同。
在Mediator模式中,虽然也会发送通知,不过那不过是为了对Colleague角色进行仲裁而已。
而在Observer模式中,将Subject角色的状态变化通知给Observer角色的目的则主要是为了使Subject角色和Observer角色同步。

UML

类图:

Code

  • Observer 、NumberGenerator
public interface Observer {

    /**
     * 通知concreateObserver
     * @param numberGenerator
     */
    void update(NumberGenerator numberGenerator);
}

public abstract class NumberGenerator {

    private List<Observer> observers=new ArrayList<>();

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

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

    /**
     * 通知所有的观察者
     */
    protected void notifyObservers(){
        Iterator<Observer> it = observers.iterator();
        while (it.hasNext()){
            Observer next = it.next();
            next.update(this);
        }
    }

    /**
     * 获取数值
     */
    public abstract int getNumber();

    /**
     * 生成数值
     */
    public abstract void excute();

}


  • Graphobserver 、Digitobserver 两个观察者
public class Digitobserver implements Observer {

    @Override
    public void update(NumberGenerator numberGenerator) {
        System.out.println(this.getClass().getName()+":"+numberGenerator.getNumber());

        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}

public class Graphobserver implements Observer {
    @Override
    public void update(NumberGenerator numberGenerator) {
        System.out.println(this.getClass().getName()+":");
        for (int i = 0; i < numberGenerator.getNumber(); i++) {
            System.out.print("*");
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}



  • RandomNumberGenerator

public class RandomNumberGenerator extends NumberGenerator{

    private Random random=new Random();

    private int number;

    @Override
    public int getNumber() {
        return number;
    }

    /**
     * 生成一次数值,通知一次观察者
     */
    @Override
    public void excute() {
        for (int i = 0; i < 20; i++) {
            number=random.nextInt(50);
            notifyObservers();
        }
    }
}


  • MainT
public class MainT {

    public static void main(String[] args) {
        NumberGenerator generator = new RandomNumberGenerator();

        // 观察者
        Digitobserver digitobserver = new Digitobserver();

        Graphobserver graphobserver = new Graphobserver();

        generator.addObserver(digitobserver);
        generator.addObserver(graphobserver);

        generator.excute();
    }
}



posted @ 2018-10-28 22:20  ---dgw博客  阅读(2033)  评论(0编辑  收藏  举报