虽然设计模式我们一般中用的很少,但是作为程序员设计模式是我们自我修养的一部分,so最近学习了一个设计模式.记下来喽:
观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
这是百科上面的原话,为了理解清楚我们上一张图
简单来说
Subject相当于任务中心 Observe 里面有很多方法继承 相当于每个实现是感知 Subject干了什么动作
当 Demo 调用Subject的时候 就会通知Observe, Observe就会被动的通知 它干了什么(肤浅的理解)
上代码,首先我们确定几个类:
1Subject类,还有Observer类是必须的
package com.hegaojian.concurrency.chapter4;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassNameSubject
* @Description TODO
* @AuthorSJ217110601
* @Date2018/7/13 16:06
* @Version 1.0
**/
public class Subject {
//一个任务里面有一堆的Observe
private List observerList = new ArrayList();
//定义一个发生变化的东西(状态)
private int state;
public int getState() {
return state;
}
public void setState(int state) {//如果这个状态没变就返回
if (state == this.state) {
return;
}
this.state = state;
notifyAllObserver();//通知其他Observer做动作
}
//附上到那Observer 也就是说添加那个Observer
public void attach(Observer observer) {
observerList.add(observer);
}
//通知到所有的
private void notifyAllObserver() {
observerList.stream().forEach(Observer::updata);
}
}
定义完之后我们应该定义Observer
public abstract class Observer {
//别人改变了数据就通知到我了 构造函数
public Observer(Subject subject) {
this.subject = subject;
//吧这个通知添加进去
subject.attach(this);
}
//定义一个任务中心
protected Subject subject;
//定义一个方法
public abstract void updata();
}
我们按照图 在定义几个Observer的子类,
public class BinaryObserver extends Observer {
public BinaryObserver(Subject subject) {
super(subject);
}
@Override
public void updata() {
System.out.println("BinaryObserver :" + Integer.toBinaryString(subject.getState()));
}
}
public class OtalObserver extends Observer {
public OtalObserver(Subject subject) {
super(subject);
}
@Override
public void updata() {
System.out.println("Otal 八进制" + Integer.toOctalString(subject.getState()));
}
}
定义了两个子类,也就是相当于模拟业务中的其他操作
public class ObserverClient {
public static void main(String[] args) {
//主题
final Subject subject = new Subject();
new BinaryObserver(subject);
new OtalObserver(subject);
System.out.println("====================");
subject.setState(10);
System.out.println("==========");
subject.setState(10);
System.out.println("============");
subject.setState(15);
}
}
我们看到上面这个类是客户扣的类,首先我们第一次赋值10,然后都去通知Observer类,去通知它我要改变了,这样就是主动通知,而Observer类则是备用接收到了通知,Subject的状态改变触发了相关事件
====================
BinaryObserver :1010
Otal 八进制12
==========
============
BinaryObserver :1111
Otal 八进制17
我们看到了输出结果,当第二次也是10的时候,它的Observer的子类不会感知到,当数字一变这样就通知了它的Observer类
==================================================================
那么在多线程的环境下怎么实现呢?
我们思路还是那个思路,这里只不过是要考虑到线程安全的问题,在这里我们模拟:根据一个List里面的id通过多线程的方式去查询数据库,但是我们得清楚的感知到线程里面的每一个动作都做到哪儿,包括知否出错等
我们先定义一个多线程的
public abstract class ObserverRunnable implements Runnable {
//(生命体征的)监听器(也就是说用这个去)
final protected LifeCycleListener listener;
//构造方法
public ObserverRunnable(LifeCycleListener listener) {
this.listener = listener;
}
//去通知被的线程
protected void NotifyChange(final RunnableEvent event) {
listener.OnEvent(event);
}
//枚举了三个类型
public enum RunnableStatu {
RUNN, ERROR, DONE
}
public static class RunnableEvent {
private final RunnableStatu runnableStatu;
//那个线程在执行它的过程中出现了问题
private final Thread thread;
//失败了的话什么原因引起的失败呢
private final Throwable throwable;
public RunnableEvent(RunnableStatu runnableStatu, Thread thread, Throwable throwable) {
this.runnableStatu = runnableStatu;
this.thread = thread;
this.throwable = throwable;
}
public RunnableStatu getRunnableStatu() {
return runnableStatu;
}
public Thread getThread() {
return thread;
}
public Throwable getThrowable() {
return throwable;
}
}
}
public interface LifeCycleListener {
//通知的方法
void OnEvent(ObserverRunnable.RunnableEvent event);
}
public class ThreaLiftListenerImpl implements LifeCycleListener {
//因为在多线程环境出现共享数据的问题所以需要枷锁 这里简单定义一下锁
private final Object LOCK = new Object();
//一个ID一个线程的去查做事情
public void concurrentQuery(List ids) {
if (ids == null || ids.isEmpty()) {
return;
}
//多线程去执行
ids.stream().forEach(id -> new Thread(new ObserverRunnable(this) {
@Override
public void run() {
try {
//正常运行
NotifyChange(new RunnableEvent(RunnableStatu.RUNN, Thread.currentThread(), null));
System.out.println("query for id " + id);
//模拟查询消耗的时间
Thread.sleep(1000L);
//正常结束
NotifyChange(new RunnableEvent(RunnableStatu.DONE, Thread.currentThread(), null));
} catch (Exception e) {
//遇到异常处理
NotifyChange(new RunnableEvent(RunnableStatu.ERROR, Thread.currentThread(), e));
}
}
}, id).start());
}
@Override
public void OnEvent(ObserverRunnable.RunnableEvent event) {
{
//这里我们加了锁,因为在多线程的环境下所以要加锁
synchronized (LOCK) {
//我们只是模拟了输出,这在业务中会写到日志里面去
System.out.println("The runnable [" + event.getThread().getName() + "] data changed and state is [" + event.getThrowable() + "]");
if (event.getThrowable() != null) {
System.out.println("The runnable [" + event.getThread().getName() + "] process failed.");
event.getThrowable().printStackTrace();
}
}
}
}
}
模拟客户端
public class CurrentListenerClient {
public static void main(String[] args) {
new ThreaLiftListenerImpl().concurrentQuery(Arrays.asList("1","2"));
}
}
The runnable [2] data changed and state is [null]
The runnable [1] data changed and state is [null]
query for id 1
query for id 2
The runnable [2] data changed and state is [null]
The runnable [1] data changed and state is [null]
输出结果的分析我,这样我们可以观察到线程里面每个数据的状态,还有对应的一些操作,那么如果遇到错误我们会怎么办?
模拟了错误
这样便可以观察到每一个线程里面的状态.
(如有错误请多指教!!!)
参考书(java多线程设计模式)
分享地址:https://pan.baidu.com/s/1jIkt94M 密码:qwb8