观察者模式及应用

xiaoxiao2026-08-12  37

观察者模式及应用 观察者模式是对象的行为模式,顾名思义,即存在观察者和被观察者。 观察者模式可以让多个观察者同时监听同一个被观察对象,当被观察对象发生变化时,并通知所有观察者,使各个观察者能作出相应的响应。适当地运用观察者模式,能提高自身代码的设计水平。   观察者模式理解和编码都比较简单,通常包括以下步骤: 1. 设计观察者接口类;   2. 观察者类实现该接口;   3. 设计被观察者抽象类,该类中提供一些方法,如:添加观察者对象,删除观察者对象,把事件通知给各个观察者对象;   4. 设计被观察者类,继承被观察者抽象类,在该类中,可以根据需要在该类中,可以定义方法:被观察者是否发生变化 一个例子 电信业务的系统中虽然全国各地的用户,能享受的服务都差不多,但是从系统层面上来说,每个地区的实现是不仅相同的。这里的原因有很多,比如各个省的系统的厂商是不一样的,即使厂商是一样的,由于每个地区所推的业务不一样,开发团队的不一样等等。 既然这么多省市,每个省所用的系统是不一样的,而不是全国使用的是同一个系统。所以每个省的系统之间必然要存在某种通讯,以便实现异地业务(比如浙江的用户在河南充值等)。如果省与省之间的系统直接进行通讯,那么这将会是个有向图(每两个点之间有且只有一条边)。这样就太复杂,而且耦合度非常高。 为了降低耦合度并且使实现更加简化,这里加入一个系统:中心系统C。各个省的系统只与中心系统C进行交互,并有中心系统C路由到目标省系统。这样就由一个有向图变成了一个单根多叶的树形结构: [img]/upload/attachment/109627/20b2b46a-ff08-37bc-b66d-e76b783d4b6f.gif[/img] 这样一来,必然存在中心系统和其他系统之间的通讯。各省的系统如果需要做异地业务,那么需要首先和中心系统通讯,由中心系统和目标的省系统进行交互,并等待其返回结果,并将结果返回给源省系统。 通讯有成功有失败,所以中心需要考核各省系统的成功率和及时率。对哪些达不到考核要求的进行扣分。而个省系统,为了满足中心系统要求的成功率和及时率,会做一些系统上的设计。 其中有一个功能,系统需要将交易中错误的笔数和超时的笔数,在最近一个小时内达到规定次数的,需要通知相关的人,以便相关人员在第一时间可以作出反映。这里的通知方式有很多种:邮件通知,短信通知,IM通知等。这里我们就讨论这个通知机制在系统中的实现。 第一种方式 先来看设计的类图。 [img]/upload/attachment/109629/94305462-6ce9-3ff9-8868-853b95503d24.gif[/img] ErrorOutput是个类,当系统发生超时,或者处理失败之后,会来调用这个类的process方法。另外,此类引用了INotify接口,在process方法里,首先会调用INofify接口的nofify方法,以达到通知相关人员的效果,然后会做一些其他的业务逻辑。而INofify的实例是通过工厂类NofifyFactory获得的。 INotify分别有三个实现类:邮件通知类(EMailNofify)、即时通讯工具通知(IMNofify)、短信方式通知(SMSNofify)。 ErrorOutput只是应用了Inofify接口,而不是具体的实现类,所以它并不知道以什么样的方式通知相关人员。这个通知方式由NofifyFactory决定。 这种方式实现的缺点: 1. 只能以一种方式通知相关人员 2. 需要等待通知程序通知完成了,才能向下执行其他逻辑。影响主程序及时性的要求。 如果需要将这个设计,硬要向观察者模式上套,那么ErrorOutput是被观察者,而INofify等是观察者。当ErrorOutput的process被调用时,就需要通知观察者对象INofify。 第二种方式 第二种方式和第一种方式没有太大的区别,只是加入了一个线程。以达到主处理逻辑和通知异步的效果,使通知程序不影响主处理程序的运行。其类图如下: [img]/upload/attachment/109631/3d957235-4b1f-37a6-b827-a555bd130996.gif[/img] 这里ErrorOutput类不再是被观察者,它只是向线程NofifyTreed类注册了“又发生了一次错误”(通过addError方法)。而NofifyTread类承担起了被观察者的角色。在线程处理的方法(run)里,扫描errorList中产生错误的错误嘛,从而决定是否需要通知观察者(INofify)。 更优雅的实现方式 观察者模式,允许向被观察者对象注册更多的观察者对象,以达到通知更多的观察者的目的。前两种实现方式中,并没有这样的功能。而是在被观察者对象里,指定了谁作为我的观察者,外部不能随意的添加和删除观察者。 在这个实现方式里,我们引入JAVA自带的观察者模式。在 java.util包下有两个类,Observable和Observer。Observable是个抽象类,承担被观察者抽象角色;Observer是个接口,承担观察者抽象角色。 所以我们不再需要接口INofify。而用Observer接口代替。 由于Observable是个抽象接口,所以这里的线程需要实现接口Runable。具体类图如下: [img]/upload/attachment/109633/10e11983-f6d1-34fc-b365-9dc726d9e4a6.gif[/img] NofifyRunable变成了被观察者的实现,同时它还实现了Runable接口。是为了通讯机制不影响主处理逻辑的运行。 具体的代码如下: ErrorOutput.java类: public class ErrorOutput { private Thread notifyThread; private NotifyRunable notifyRunable; public ErrorOutput() { notifyRunable = NotifyRunable.getInstance(); notifyRunable.addObserver(new SmsNotify()); notifyRunable.addObserver(new EMailNotify()); notifyRunable.addObserver(new IMNotify()); notifyThread = new Thread(notifyRunable); notifyThread.start(); } public void process(String errorCode) { notifyRunable.addErrorCode(errorCode); //do other thing } } NotifyRunable.java类文件: public class NotifyRunable extends Observable implements Runnable { public static void main(String[] args) { NotifyRunable runable = new NotifyRunable(); Thread thread = new Thread(runable); thread.start(); } private static NotifyRunable instance = null; private ICounter needNotifyCounter; private HashMap counterMap = null; private ArrayList errorCodeList = null; private final static Object lock = new Object(); private boolean stop = false; private NotifyRunable() { needNotifyCounter = createCounter(); counterMap = new HashMap(); errorCodeList = new ArrayList(); } private static ICounter createCounter() { return new IntervalCounter(DisasterToleranceUtil.getNotifyInterval() * 1000); } public static NotifyRunable getInstance() { if (instance == null) { instance = new NotifyRunable(); } return instance; } public void addErrorCode(int errorCode) { if (!DisasterToleranceUtil.isDisasterToleranceErrorCode(errorCode)) { return; } synchronized (lock) { errorCodeList.add(String.valueOf(errorCode)); } } private void slep(long l) { try { Thread.sleep(l); } catch (Exception e) { //do nothing } } public void run() { while (true) { while (!stop) { ArrayList list = new ArrayList(); synchronized (lock) { if (errorCodeList.size() > 0) { list = new ArrayList(errorCodeList.size()); moveList(errorCodeList, list); } } processNotify(list); slep(3 * 1000); } slep(120 * 1000); } } private void moveList(ArrayList src, ArrayList dst) { for (int i = src.size() - 1; i >= 0; i--) { dst.add(src.remove(i)); } } private void processNotify(ArrayList list) { for (int i = list.size() - 1; i >= 0; i--) { long times = needNotifyCounter.plus(); String message = "在过去" + DisasterToleranceUtil.getNotifyInterval() + "秒时间内,已经发生" + times + "次容灾!最大次数为:" + DisasterToleranceUtil.getMaxToleranceTimes(); if (CBossLogUtil.getLogger(this.getClass()).isDebugEnabled()) { CBossLogUtil.getLogger(this.getClass()).debug(message); } String errorCode = (String) list.get(i); ICounter counter = (ICounter) counterMap.get(errorCode); if (counter == null) { counter = createCounter(); counter.setName(errorCode); counterMap.put(errorCode, counter); } counter.plus(); if (times > DisasterToleranceUtil.getMaxToleranceTimes()) { sendMesssage(); } } } private void sendMesssage() { if (CBossLogUtil.getLogger(this.getClass()).isInfoEnabled()) { CBossLogUtil.getLogger(this.getClass()).info("发通知给相关人员"); } String message = "在过去" + DisasterToleranceUtil.getNotifyInterval() + "秒时间内,已经发生" + needNotifyCounter.getCurrentCount() + "次错误!"; message += "其中"; ICounter[] counter = (ICounter[]) counterMap.values().toArray(new ICounter[counterMap.size()]); message += sortString(counter); try { setChanged(); notifyObservers("系统通知你!" + message); } catch (Exception e) { System.out.println("发通知失败!"+e); } } private String sortString(ICounter[] counters) { for (int i = 0; i < counters.length; i++) { for (int j = i + 1; j < counters.length; j++) { if (counters[i].getCurrentCount() < counters[j].getCurrentCount()) { ICounter tmp = counters[i]; counters[i] = counters[j]; counters[j] = tmp; } } } int num = counters.length > 5 ? 5 : counters.length; String[] message = new String[num]; for (int i = 0; i < num; i++) { ICounter counter = counters[i]; message[i] = counters[i].getName() + "=" + counter.getCurrentCount(); } return StringUtils.join(message, ","); } Observer的实现类就不再描述了。
转载请注明原文地址: https://www.6miu.com/read-5051097.html

最新回复(0)