天天看点

设计模式-观察者模式 发布/订阅模式

设计模式-观察者模式 发布/订阅模式

代码

观察者接口

public interface IHanFeiZi{ // 当吃早饭时 public void havBreakFast(); // 进行娱乐活动时 public void haveFun(); }           

具体的被观察者

public class HanFeiZi implements IHanFeiZi{ `// 根据是否在吃饭,作为监控的标准 private boolean isHavingBreakfast = false; // 判断是否在娱乐 private boolean isHavingFun = false; // 当吃饭的时候 public void haveBreakfast(){ System.out.println("吃饭了"); this.isHavingBreakfast = true; } // 当开始娱乐的时候 public void haveFun(){ System.out.println("开始娱乐"); this.isHavingFun = true; } // 下方位get/set省去 }           

观察者

public interface ILiSi{ // 发行有人有动静,进行行动 public void update(String context); }

public class LiSi implements ILiSi{ // 首先他为一个观察者 public void update(String str){ System.out.println("观察到某人活动,进行汇报"); this.reportToQinShiHuang(str); // 调用汇报方法 System.out.println("汇报完毕"); } // 进行汇报、 private void reportToQinShiHuang(String reportContext){ System.out.println("进行汇报"); } }           

最后定义中间

class Spy extends Thread{ private HanFeiZi hanFeiZi; private LiSi liSi; private String type; // 通过构造函数注入,显示将要监控谁 public Spy(HanFeiZi _hanFeiZi, LiSi _liSi, String _type){ this.hanFeiZi = _hanFeiZi; this.liSi = _liSi; this.type = _type; } @Override public void run(){ while(true){ if(this.type.equals("breakfast")){ // 监控是否吃早餐 // 如果在吃饭,则通知 if(this.hanFeiZi.isHavingBreakfast()){ this.liSi.update("在吃饭"); // 重置状态,继续监控 this.hanFeiZi.setHavingBreakfast(false); } }else{ // 判断是否在娱乐 if(this.hanFeiZi.isHavingFun()){ this.liSi.update("在娱乐"); this.hanFeiZi.setHavingFun(false); } } } } }           

场景类

public class Client{ public static void main(String[] args) throws interruptedException { // 定义两个人 LiSi liSi = new LiSi(); HanFeiZi hanFeiZi = new HanFeiZi(); // 观察早餐 Spy watchBreakfast = new Spy(hanFeiZi, lisi, "breakfast"); watchBreak.start(); // 启动线程、https://www.iming.info/2019/01/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F-%E5%8F%91%E5%B8%83-%E8%AE%A2%E9%98%85%E6%A8%A1%E5%BC%8F/ // 继续查看都干什么 Thread.sleep(1000); hanFeiZi.haveBreakfast(); // 开始吃饭 // 如果娱乐 Thread.sleep(1000); hanFeiZi.haveFun(); // 查看情况 } }           

修改

由于上面使用了一个死循环,会导致出现问题。并且由于多线程的缘故,会导致数据的污染问题,根本无法使用。

修改如下

public class HanFeiZi implements IHanFeiZi{ // 声明李 private ILiSi lisi = new LiSi(); // 当吃饭的时候 public void hanveBreakfast(){ System.out.println("吃饭开始"); this.liSi.update("吃饭了"); } // 当娱乐的时候 public void haveFun(){ System.out.println("开始娱乐"); this.liSi.update("在娱乐"); } }




最后书写场景类




public class Client{ public static void main(String[] args){ // 定义出韩 HanFeiZi hanFeiZi = new HanFeiZi(); // 继续查看韩在干什么 hanFeiZi.haveBreakfast(); // 当其娱乐 hanFeiZi.haveFun(); } }           

继续改进

如果这样聚合,如果有一堆人需要监控被观察者,这样不行,不能一个监控一个,如果此时要修改其他的监控内容,那么都要修改,违反开闭原则

开闭原则 对扩展开放,对修改关闭

那么,将被观察者的自身活动定义一个接口,被观察者定义接口,在统一的类HanFeiZi中实现该接口,对于观察者来说,定义一个观察者的接口,然后多名观察者分别实现该类

被观察者

public interface Observable { // 增加一个观察者 public void addObserver(Observer observer); // 删除一个观察者 public void deleteObserver(Observer observer); // 当发生动作的时候,通知观察者 public void notifyObservers(String context); }

上方是一个统一的观察者接口,所有的观察者都能实现这个接口。继续查看被观察者

public class HanFeiZi implements Observalbe, IHanFeiZi{ // 定义数组,用于保存观察者 private ArrayList observerList = new ArrayList(); // 增加观察者 public void addObserver(Observer observer){ this.observerList.add(observer); } // 删除观察者 public void deleteObserver(Observer observer){ this.observerList.remove(observer); } // 通知所有的观察者 public void notifyObservers(String context){ for(Observer observer:observerList){ observer.update(context); } } // 当要吃饭了 public void haveBreakfast(){ System.out.println("吃饭"); // 通知观察者 this.notifyObservers("在吃饭"); } // 开始娱乐 public void haveFun(){ System.out.println("开始娱乐"); this.notifyObservers("在娱乐"); } }

// 书写观察者接口 public interface Observer{ // 发现动静,进行行动 poublic void update(String context); }

// 书写三个观察者,只需要实现观察者的接口即可 public class LiSi implements Observer{ // 首先要为观察者 public void update(String str){ System.out.println("开始活动了"); // 汇报 this.reportToQinShiHuang(str); System.out.println("汇报完毕"); } // 汇报 private void reportToQinShiHuang(String reportContext){ System.out.println("进行汇报"); } }           

同理,需要观察者直接实现接口即可。

public class Client{ public static void main(String[] args){ // 定义三个观察者 Observer liSi = new LiSi(); Observer wangSi = new WangSi(); Observer liuSi = new LiuSi(); // 定义被观察的 HanFeiZi hanFeiZi = new HanFeiZi(); // 当三个人观察韩的时候 hanFeiZi.addObserver(liSi); hanFeiZi.addObserver(wangSi); hanFeiZi.addObserver(liuSi); // 然后查看在干什么 hanFeiZi.haveBreakfast(); } }           

这样就完成了观察者模式,当被观察的发生改变的时候,通知被通过构造方法注入的观察者,此观察者保存在动态数组中,然后当被观察者发生改变的时候,只需要使用循环通知保存在数组中的观察者即可。

订阅/发布模型