观察者设计模式


前言

从本节内容开始我们要正式进入并发编程设计模式的学习了,首先讲的是观察者设计模式,我们先从java的设计模式开始,然后再过度到并发编程的观察者模式


一、什么是观察者设计模式?

关于什么是观察者模式?我的理解是这样的。首先观察者模式有观察者这么个角色,既然有观察者,那么就有被观察者。然后这个模式强调的是观察者两个字。也就是观察者实时观察这被观察者的一举一动。一旦被观察者的状态发生改变,那么所有的观察者就会做出相应的动作。而经过网上相关资料的查找,我对其又有了更深刻的理解:观察者又称为发布-订阅者模式,发布者作为被观察的对象,而订阅者是观察者。

二、应用场景

最典型常见的的应用场景就是:微博订阅、关注微信公众号了。一旦发被关注的微博或者微信公众号发布了新消息,那么关注的账号就会看到发布小消息。发布消息其实就是一个通知过程。

三、java观察者模式例子

1.被观察者(发布者)

发布者,也就是事件源。被观察者首先应该具备观察者的属性,可以是单个,也可以是列表。然后发布者要有状态属性,可以设置或者获取状态。被观察者状态改变就会通知观察者。要想通知观察者,被观察者就得具备通知方法。还有最重要的一点被观察者要具备注册方法,简单来讲就是被订阅方法,这样订阅者才能订阅发布者。具体代码如下

package observer;

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

public class Subject {
    private Integer state;

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

    public Integer getState() {
        return this.state;
    }

    public void setState(Integer state) {
        if (this.getState().equals(state)) {
            return;
        }
        notifyObServer(state);
    }

    public void attach (Observer observer) {
        this.observerList.add(observer);
    }

    private void notifyObServer(Integer state) {
        this.state = state;
        observerList.forEach(Observer::update);
    }


}

2.观察者(订阅者)

观察者可以有多个,所以就需要用到接口或者抽象类去实现解耦合。观察者被新建的时候要将自己注册到发布者里(订阅过程:将自己添加到被观察者的观察者列表里),然后观察者被发布者通知之后就要将做出响应,所以观察者要有响应方法。

package observer;

public abstract class Observer {

    protected Subject subject;

    Observer(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    public abstract void update();
}


package observer;

public class BinaryObserver extends Observer {
    public BinaryObserver(Subject subject) {
        super(subject);
    }

    @Override
    public void update() {
        System.out.println("binary String: " + Integer.toBinaryString(subject.getState()));
    }
}

package observer;

public class OctalObserver extends Observer {

    public OctalObserver(Subject subject) {
        super(subject);
    }

    @Override
    public void update() {
        System.out.println("octal String: " + Integer.toOctalString(subject.getState()));
    }
}

3.客户端

package observer;

public class client {
    public static void main(String[] args) {
        Subject subject = new Subject();
        new BinaryObserver(subject);
        new OctalObserver(subject);
        System.out.println("======================");
        subject.setState(10);
        System.out.println("======================");
        System.out.println("======================");
        subject.setState(10);
        System.out.println("======================");
        System.out.println("======================");
        subject.setState(12);
        System.out.println("======================");
    }
}

三、java观察者模式在多线程中的应用

1.被观察的线程

我们这里定义实现Runnable的抽象类。跟上面一样,作为被观察者,首先要有观察者的属性,可以是一个或者多个,这里我们简单点,使用一对一的关系。其次也同样要有注册方法,这个跟上面稍微有点不一样,这里选择新建Runnable的时候将观察者注册进来,也就是在构造方法中实现。最后,同样要有通知方法。

package threadobserver;

/**
 * 需求:观察线程的生命周期
 * 1、可被观察的Runnable
 * 2、线程生命周期观察者(接口与实现类)
 */
public abstract class ObserverableRunnable implements Runnable {
    /**
     * 1、定义观察者
     * 2、定义通知方法
     */
    private final LifecycleListener listener;

    public ObserverableRunnable(final LifecycleListener listener) {
        this.listener = listener;
    }

    public void notifyObserver(final RunnableEvent event) {
        this.listener.onEvent(event);
    }

    enum RunnableState {
        RUNNING, DONE, ERROR;
    }

    class RunnableEvent {
        private RunnableState state;
        private Thread thread;
        private Throwable cause;

        public RunnableEvent(RunnableState state, Thread thread, Throwable cause) {
            this.state = state;
            this.thread = thread;
            this.cause = cause;
        }

        public RunnableState getState() {
            return state;
        }

        public void setState(RunnableState state) {
            this.state = state;
        }

        public Thread getThread() {
            return thread;
        }

        public void setThread(Thread thread) {
            this.thread = thread;
        }

        public Throwable getCause() {
            return cause;
        }

        public void setCause(Throwable cause) {
            this.cause = cause;
        }
    }
}

2.观察者(监听者)

同样,如果要实现被观察者与观察者的一对多关系,就要用到接口或者抽象类实现解耦合,这里使用接口,接口只定义响应方法。然后;创建接口的实现类,实现响应方法。另外观察者还要添加创建并启动线程的方法,然后将自己注册进Runnable中实现监听。而线程要做的就是调用Runnable的通知方法(方法体里是观察者的响应方法)。这样,只要被观察者已调用通知方法,观察者就会做出响应。

package threadobserver;

public interface LifecycleListener {
    void onEvent(ObserverableRunnable.RunnableEvent event);
}

package threadobserver;

import java.util.List;

/**
 * 生命周期观察者
 */
public class LifecycleListenerObserver implements LifecycleListener{
    /**
     * 1、实现onEvent方法
     * 2、提供创建线程的方法
     */

    private static final Object LOCK = new Object();

    public void concurrentQuery(List<String> ids) {
        ids.forEach(x -> {
            new Thread(new ObserverableRunnable(this) {
                @Override
                public void run() {
                    try {
                        notifyObserver(new RunnableEvent(RunnableState.RUNNING, Thread.currentThread(), null));
//                        Thread.sleep(10L);
                        notifyObserver(new RunnableEvent(RunnableState.DONE, Thread.currentThread(), null));
                    } catch (Throwable e) {
                        notifyObserver(new RunnableEvent(RunnableState.ERROR, Thread.currentThread(), e));
                    }
                }
            }, x).start();
        });
    }



    /**
     *
     * @param event
     */
    @Override
    public void onEvent(ObserverableRunnable.RunnableEvent event) {
        System.out.println("当前线程【"+ event.getThread().getName() +"】" + "changed state and current state is 【"+ event.getState() +"】");
        if (event.getCause() != null) {
            System.out.println("The runnable [" + event.getThread().getName() + "] process failed.");
            event.getCause().printStackTrace();
        }
    }
}

3.客户端

package threadobserver;

import java.util.Arrays;

public class client {
    public static void main(String[] args) {
        new LifecycleListenerObserver().concurrentQuery(Arrays.asList("1", "2", "3", "4"));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值