设计模式

【设计模式】之观察者模式

2018-10-30  本文已影响0人  锕123

观察者模式

什么是观察者模式

观察者模式的特点

观察者模式的使用场景

观察者模式类图

Observer-Design-Pattern-Class-Diagram.png

观察者模式示例

在这个示例中,描述了新闻发布者。在典型的流程中,新闻阅读者订阅新闻。
一单一个新的新闻被出版商发布了,所有的观察者都会收到通知。
在这里出版商的角色就是一个主体,订阅者就是观察者。
一个出版商可以有一个或者多个订阅者。

上面的类图中表现了2个观察者 Subscriber1Subscriber2均注册到了publisher。
一旦Publisher状态发生变更,两个订阅者都会收到通知。

Observer.java

package org.byron4j.cookbook.designpattern.observer;

/**
 * 观察者接口类
 */
public interface Observer {
    public void update(String editon);
}

Subscriber1.java

package org.byron4j.cookbook.designpattern.observer;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

/**
 * 观察者1
 */
@AllArgsConstructor
@Data
@Builder
public class Subscriber1 implements  Observer {
    @Override
    public void update(String editon) {
        System.out.println("Subscriber1收到新的版本通知。" + editon);
    }
}

Subscriber2.java

package org.byron4j.cookbook.designpattern.observer;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

/**
 * 观察者2
 */
@AllArgsConstructor
@Data
@Builder
public class Subscriber2 implements  Observer {
    @Override
    public void update(String editon) {
        System.out.println("Subscriber2收到新的版本通知。" + editon);
    }
}

Subject.java

package org.byron4j.cookbook.designpattern.observer;

/**
 * 主体
 */
public interface Subject {

    /**
     * 注册主体
     * @param observer
     */
    public void registerObserver(Observer observer);

    /**
     * 移除订阅
     * @param observer
     */
    public void removeObserver(Observer observer);

    /**
     * 移除所有的观察者
     */
    public void notifyObservers();

    /**
     * 初始化主体相关信息
     */
    public void initObservers();
}

Publisher.java

package org.byron4j.cookbook.designpattern.observer;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

/**
 * 出版商--发布者
 */

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Publisher implements Subject{

    /**
     * 已注册的观察者列表
     */
    private List<Observer> _observers = new ArrayList<>();



    @Override
    public void registerObserver(Observer observer) {
        System.out.println("注册观察者:" + observer);
        _observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        System.out.println("注销观察者:" + observer);
        _observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : _observers) {
            observer.update("广播消息通知给:" + observer);
        }
    }

    @Override
    public void initObservers() {
        if( null == _observers ){
            _observers = new ArrayList<>();
        }
    }
}

ObserverTest.java

package org.byron4j.cookbook.designpattern;

import org.byron4j.cookbook.designpattern.observer.*;
import org.junit.Test;

public class ObserverTest {

    @Test
    public void test(){

        // 主体
        Subject publisher = Publisher.builder().build();
        publisher.initObservers();

        // 观察者注册
        Observer subscriber1 = Subscriber1.builder().build();
        publisher.registerObserver(subscriber1);

        Observer subscriber2= Subscriber2.builder().build();
        publisher.registerObserver(subscriber2);

        // 通知当前已注册的观察者
        publisher.notifyObservers();

        // 移除观察者
        publisher.removeObserver(subscriber2);

        // 通知当前已注册的观察者
        publisher.notifyObservers();
    }


}

测试用例输出结果

注册观察者:Subscriber1()
注册观察者:Subscriber2()
Subscriber1收到新的版本通知。广播消息通知给:Subscriber1()
Subscriber2收到新的版本通知。广播消息通知给:Subscriber2()
注销观察者:Subscriber2()
Subscriber1收到新的版本通知。广播消息通知给:Subscriber1()

观察者模式的优点

观察者模式的缺陷

经验法则

弱引用版本实现主体

package org.byron4j.cookbook.designpattern.observer;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
 * 出版商--发布者---弱引用观察者列表--防止内存泄漏
 */

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Publisher2WeakReference implements Subject{

    /**
     * 已注册的观察者列表
     */
    private List<WeakReference<Observer>> _observers = new ArrayList<>();



    @Override
    public void registerObserver(Observer observer) {
        System.out.println("注册观察者:" + observer);
        _observers.add(new WeakReference<Observer>(observer));
    }

    @Override
    public void removeObserver(Observer observer) {
        System.out.println("注销观察者:" + observer);
        _observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (WeakReference<Observer> observer : _observers) {
            observer.get().update("广播消息通知给:" + observer.get());
        }
    }

    @Override
    public void initObservers() {
        if( null == _observers ){
            _observers = new ArrayList<>();
        }
    }
}

观察者模式的另一个示例


abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

class Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public void add(Observer o) {
        observers.add(o);
    }

    public int getState() {
        return state;
    }

    public void setState(int value) {
        this.state = value;
        execute();
    }

    private void execute() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

class HexObserver extends Observer {
    public HexObserver(Subject subject) {
        this.subject = subject;
        this.subject.add(this);
    }

    public void update() {
        System.out.print(" " + Integer.toHexString(subject.getState()));
    }
}

class OctObserver extends Observer {
    public OctObserver(Subject subject) {
        this.subject = subject;
        this.subject.add( this );
    }

    public void update() {
        System.out.print(" " + Integer.toOctalString(subject.getState()));
    }
}

class BinObserver extends Observer {
    public BinObserver(Subject subject) {
        this.subject = subject;
        this.subject.add(this);
    }

    public void update() {
        System.out.print(" " + Integer.toBinaryString(subject.getState()));
    }
}

public class ObserverTest {
    public static void main( String[] args ) {
        Subject sub = new Subject();
        // Client configures the number and type of Observers
        new HexObserver(sub);
        new OctObserver(sub);
        new BinObserver(sub);
        Scanner scan = new Scanner(System.in);
        for (int i = 0; i < 5; i++) {
            System.out.print("\nEnter a number: ");
            sub.setState(scan.nextInt());
        }
    }
}

上一篇下一篇

猜你喜欢

热点阅读