Observer pattern (Observer)

1. Definitions

Defines a one-to-many dependency between objects. When an object's state changes, all objects that depend on it are notified and updated automatically.

2. Structure

write picture description here

  • Subject: The target object, which usually has the following functions.
    a. A target can be observed by multiple observers
    b. The target provides maintenance of observer registration and unsubscription
    c. Notifies all registered valid observers when the state of the target object changes.
  • Observer: Define the interface of the observer, and provide the corresponding update method when the target notification is provided. This update method processes the corresponding business. In this method, the target object can be called back to obtain the data of the target object.
  • ConcreteSubject: The specific target implementation object is used to maintain the target state. When the state of the target object changes, all registrants and valid observers are notified, and the observers can perform corresponding processing.
  • ConcreteObserver: The specific implementation object of the observer, which is used to receive notifications from the target object and perform corresponding follow-up processing, such as updating its own state to be consistent with the target state.

3. Examples

WeChat official account subscription official account topic is (Subject) followers are observers (Observer) an official account topic. When the official account topic publishes some articles, it will notify all followers that there are multiple subscribers. When the official account topic publishes some articles, it will notify all followers. The following uses JAVA code to simulate this process!

VipcnSubject


/**
 * 微信公众号主题
 *
 * @author lijun
 * @since 2018-03-23 13:31
 */
public class VipcnSubject {

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

    /**
     * 关注
     *
     * @param observer 观察者
     */
    public void attention(VipcnObserver observer) {
        observers.add(observer);
    }

    /**
     * 取消关注
     *
     * @param observer
     */
    public void canelAttention(VipcnObserver observer) {
        observers.remove(observer);
    }

    /**
     * 通知所有的订阅者
     */
    public void notifyVipcnObserver() {
        observers.stream().forEach(observer -> observer.view(this));
    }
}

CsdnVipcnSubject

/**
 * CSDN公众号主题  当发布文章后通知订阅者
 *
 * @author lijun
 * @since 2018-03-23 13:41
 */
public class CsdnVipcnSubject extends VipcnSubject {
    /**
     * 文章
     */
    private String context;


    public String getContext() {
        return context;
    }

    /**
     * 发布文章
     *
     * @param context 文章内容
     */
    public void publishContext(String context) {
        this.context = context;
        this.notifyVipcnObserver();
    }
}

VipcnObserver

/**
 * 关注者接口
 *
 * @author lijun
 * @since 2018-03-23 13:33
 */
public interface VipcnObserver {
    /**
     * 查看文章
     */
    void view(VipcnSubject subject);
}

VipcnObserverA

/**
 * 关注者A
 *
 * @author lijun
 * @since 2018-03-23 13:58
 */
public class VipcnObserverA implements VipcnObserver {

    /**
     * 文章
     */
    private String context;

    /**
     * 查看文章
     */
    @Override
    public void view(VipcnSubject subject) {
        CsdnVipcnSubject csdnVipcnSubject = (CsdnVipcnSubject) subject;
        context = csdnVipcnSubject.getContext();
        System.out.println("我是订阅者A,我收到了文章.文章内容是:" + context);
    }
}

VipcnObserverB

/**
 * 关注者B
 *
 * @author lijun
 * @since 2018-03-23 13:58
 */
public class VipcnObserverB implements VipcnObserver {

    /**
     * 文章
     */
    private String context;

    /**
     * 查看文章
     */
    @Override
    public void view(VipcnSubject subject) {
        CsdnVipcnSubject csdnVipcnSubject = (CsdnVipcnSubject) subject;
        context = csdnVipcnSubject.getContext();
        System.out.println("我是关注者B,我收到了文章.文章内容是:" + context);
    }
}

test

    @Test
    public void testVipcn() {

        CsdnVipcnSubject subject = new CsdnVipcnSubject();
        //关注
        subject.attention(new VipcnObserverA());
        subject.attention(new VipcnObserverB());

        //发布文章
        subject.publishContext("Spring5.0源码导入IDEA(一)");
    }

output:

我是订阅者A,我收到了文章.文章内容是:Spring5.0源码导入IDEA(一)
我是关注者B,我收到了文章.文章内容是:Spring5.0源码导入IDEA(一)

In fact, there is already a partial implementation of the observer pattern in JAVA. Most of the functions of the target class are implemented in the java.util.Observable class. The update interface is defined in the java.util.Observer interface, which is the interface of the observer. The following example is implemented through a partial implementation of the observer pattern that comes with JAVA.

CsdnVipcnSubjectJava

/**
 * CSDN公众号主题  当发布文章后通知订阅者
 * @author lijun
 * @since 2018-03-23 16:41
 */
public class CsdnVipcnSubjectJava extends Observable {
    /**
     * 文章
     */
    private String context;


    public String getContext() {
        return context;
    }

    /**
     * 发布文章
     *
     * @param context 文章内容
     */
    public void publishContext(String context) {
        this.context = context;
        //下面这这一部必须有
        this.setChanged();
        this.notifyObservers(this.context);
    }
}

VipcnObserverJavaA

/**
 * 关注者A
 *
 * @author lijun
 * @since 2018-03-23 13:58
 */
public class VipcnObserverJavaA implements Observer {

    /**
     * 文章
     */
    private String context;


    /**
     * 查看文章
     */
    @Override
    public void update(Observable o, Object arg) {
       /* CsdnVipcnSubjectJava csdnVipcnSubject = (CsdnVipcnSubjectJava)o;
        context = csdnVipcnSubject.getContext();*/
        System.out.println("我是订阅者A,我收到了文章.文章内容是:" + arg);
    }
}

VipcnObserverJavaB

/**
 * 关注者B
 *
 * @author lijun
 * @since 2018-03-23 13:58
 */
public class VipcnObserverJavaB implements Observer {

    /**
     * 文章
     */
    private String context;


    /**
     * 查看文章
     */
    @Override
    public void update(Observable o, Object arg) {
      /*  CsdnVipcnSubjectJava csdnVipcnSubject = (CsdnVipcnSubjectJava)o;
        context = csdnVipcnSubject.getContext();*/

        System.out.println("我是订阅者A,我收到了文章.文章内容是:" + arg);
    }
}

test

    @Test
    public void testVipcnJava() {

        CsdnVipcnSubjectJava subject = new CsdnVipcnSubjectJava();
        //关注
        subject.addObserver(new VipcnObserverJavaA());
        subject.addObserver(new VipcnObserverJavaB());

        //发布文章
        subject.publishContext("Spring5.0源码导入IDEA(一)");
    }

output:

我是订阅者A,我收到了文章.文章内容是:Spring5.0源码导入IDEA(一)
我是关注者B,我收到了文章.文章内容是:Spring5.0源码导入IDEA(一)

The result is the same as the example above.

There is another slightly deformed implementation of the above example:

Event

/**
 * 事件
 * @author lijun
 * @since 2018-03-23 14:51
 */
public class Event {

    //事件源
    private Object source;
    //通知目标
    private Object target;
    //回调
    private Method callback;
    //触发
    private String trigger;

    private long time;

    public Event(Object target, Method callback) {
        this.target = target;
        this.callback = callback;
    }


    public Object getSource() {
        return source;
    }


    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Method getCallback() {
        return callback;
    }

    public void setCallback(Method callback) {
        this.callback = callback;
    }

    public String getTrigger() {
        return trigger;
    }

    @Override
    public String toString() {
        return "Event{" +
                "\n\tsource=" + source + ",\n" +
                "\ttarget=" + target + ",\n" +
                "\tcallback=" + callback + ",\n" +
                "\ttrigger='" + trigger + '\'' + "\n" +
                '}';
    }

    public long getTime() {
        return time;
    }

    Event setTime(long time) {
        this.time = time;
        return this;
    }

    Event setSource(Object source) {
        this.source = source;
        return this;
    }

    Event setTrigger(String trigger) {
        this.trigger = trigger;
        return this;
    }
}

EventLisenter


/**
 * 事件的注册和监听
 *
 * @author lijun
 * @since 2018-03-23 15:07
 */
public class EventLisenter {

    /**
     * Map相当于是一个注册器
     */
    protected Map<Enum, Event> events = new HashMap<Enum, Event>();

    /**
     * 注册事件
     *
     * @param eventType eventType
     * @param target    target
     * @param callback  callback
     */
    public void addLisenter(Enum eventType, Object target, Method callback) {
        //注册事件
        //用反射调用这个方法
        events.put(eventType, new Event(target, callback));
    }

    /**
     * 触发事件
     *
     * @param e
     */
    private void trigger(Event e) {
        e.setSource(this);
        e.setTime(System.currentTimeMillis());

        try {
            e.getCallback().invoke(e.getTarget(), e);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }


    protected void trigger(Enum call) {
        if (!this.events.containsKey(call)) {
            return;
        }
        trigger(this.events.get(call).setTrigger(call.toString()));
    }

}

CsdnVipcnSubjectSelf


/**
 * 被观察者
 *
 * @author lijun
 * @since 2018-03-23 15:42
 */
public class CsdnVipcnSubjectSelf extends EventLisenter {
    /**
     * 文章或者文字类容
     */
    private String context;

    public String getContext() {
        return context;
    }

    /**
     * 发布文章
     *
     * @param context 内容
     */
    public void publishArtcle(String context) {
        this.context = context;
        System.out.println("发布文章。。。。");
        this.trigger(VipcnEventType.PUBLISH_ARTICLE);
    }


    /**
     * 发布文字
     *
     * @param context 内容
     */
    public void publishArtcleText(String context) {
        this.context = context;
        System.out.println("发布文字。。。。");
        this.trigger(VipcnEventType.PUBLISH_TEXT);
    }

}

VipcnEventType

/**
 * 事件枚举
 * @author lijun
 * @since 2018-03-23 15:11
 */
public enum VipcnEventType {
    PUBLISH_ARTICLE,
    PUBLISH_TEXT;
}

VipcnEventCallback

/**
 * 观察者
 * 回调响应的逻辑,由自己实现
 *
 * @author lijun
 * @since 2018-03-23 15:20
 */
public class VipcnEventCallback {

    /**
     * 发布文件的通知
     *
     * @param e 事件
     */
    public void publishArticle(Event e) {
        System.out.println("观察者收到发布的文章,文章内容是:" + ((CsdnVipcnSubjectSelf) e.getSource()).getContext());
    }

    /**
     * 发布文件的通知
     *
     * @param e 事件
     */
    public void publishText(Event e) {
        System.out.println("观察者收到发布的文字,文字内容是:" + ((CsdnVipcnSubjectSelf) e.getSource()).getContext());
    }

}

test:

 @Test
    public void testWechatCore() {
        try {

            VipcnEventCallback callback = new VipcnEventCallback();

            Method publishArticle = VipcnEventCallback.class.getMethod("publishArticle", Event.class);

            Method publishText = VipcnEventCallback.class.getMethod("publishText", Event.class);


            CsdnVipcnSubjectSelf csdnVipcnSubjectCore = new CsdnVipcnSubjectSelf();

            //添加发布文章的监听
            csdnVipcnSubjectCore.addLisenter(VipcnEventType.PUBLISH_ARTICLE, callback, publishArticle);

            //添加发布文字的监听
            csdnVipcnSubjectCore.addLisenter(VipcnEventType.PUBLISH_TEXT, callback, publishText);

            csdnVipcnSubjectCore.publishArtcle("Spring5.0源码导入IDEA(一)");
            csdnVipcnSubjectCore.publishArtcleText("今天晚上发红包!");

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

output:

发布文章。。。。
观察者收到发布的文章,文章内容是:Spring5.0源码导入IDEA(一)
发布文字。。。。
观察者收到发布的文字,文字内容是:今天晚上发红包!

4. Essence

Trigger linkage.

5. Summary

  1. advantage
    • Observer pattern achieves abstract coupling between observer and target
    • Observer realizes dynamic linkage
    • Observer mode supports broadcast communication
  2. shortcoming
    • May cause unnecessary operations

Source address

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325582498&siteId=291194637