设计模式对阅读源码的重要性不言而喻,所以,我准备一边阅读源码一边学习设计模式。今天从观察者模式开始学起。
定义和结构
观察者(Observer)模式又称发布-订阅模式,发布者发布消息,订阅者接受消息,《设计模式》中给出的定义是:定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
观察者模式类图
观察者模式的组成部分:
1. 抽象目标角色(Subject):目标角色知道它的观察者,可以有任意多个观察者观察同一个目标。并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口实现。
2. 抽象观察者角色(Observer):为那些在目标发生改变时需要获得通知的对象定义一个更新接口。抽象观察者角色主要有抽象类或者接口实现。‘
3. 具体目标角色(Concrete Subject):将有关状态存入各个Concrete Observer 对象。当它的状态发生改变时,向它的各个观察者发出通知。
4. 具体观察者角色(Concete Observer):存储有关状态,这些状态应与目标的状态保持一致。实现Observer的更新接口以使自身状态与目标的状态保持一致。在本角色内也可以维护一个指向Concrete Subject对象的引用。
应用场景
对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
在junit中的应用实例
TestListener在junit中充当抽象观察者角色(Observer),其定义了四个update 方法。
public interface TestListener { /** * An error occurred. */ public void addError(Test test, Throwable t); /** * A failure occurred. */ public void addFailure(Test test, AssertionFailedError t); /** * A test ended. */ public void endTest(Test test); /** * A test started. */ public void startTest(Test test); }
ResultPrinter类在junit中充当具体观察者角色(Concete Observer)。
public class ResultPrinter implements TestListener { //省略无关代码 ...... /** * @see junit.framework.TestListener#addError(Test, Throwable) */ public void addError(Test test, Throwable t) { getWriter().print("E"); } /** * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError) */ public void addFailure(Test test, AssertionFailedError t) { getWriter().print("F"); } /** * @see junit.framework.TestListener#endTest(Test) */ public void endTest(Test test) { } /** * @see junit.framework.TestListener#startTest(Test) */ public void startTest(Test test) { getWriter().print("."); if (fColumn++ >= 40) { getWriter().println(); fColumn= 0; } } // 省略无关代码 ..... }
TestResult 在junit中充当的是目标角色。由于junit功能简单,所以junit中只有一个具体目标角色
public class TestResult extends Object { //这个是用来存放测试Failures的集合 protected Vector fFailures; //这个是用来存放测试Errors的集合 protected Vector fErrors; //这个就是用来存放注册进来的观察者的集合 protected Vector fListeners; protected int fRunTests; private boolean fStop; public TestResult() { fFailures= new Vector(); fErrors= new Vector(); fListeners= new Vector(); fRunTests= 0; fStop= false; } /** * Adds an error to the list of errors. The passed in exception * caused the error. */ public synchronized void addError(Test test, Throwable t) { fErrors.addElement(new TestFailure(test, t)); //下面就是通知各个观察者的addError方法 for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).addError(test, t); } } /** * Adds a failure to the list of failures. The passed in exception * caused the failure. */ public synchronized void addFailure(Test test, AssertionFailedError t) { fFailures.addElement(new TestFailure(test, t)); //下面就是通知各个观察者的addFailure方法 for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).addFailure(test, t); } } /** * Registers a TestListener * 注册一个观察者 */ public synchronized void addListener(TestListener listener) { fListeners.addElement(listener); } /** * Unregisters a TestListener * 删除一个观察者 */ public synchronized void removeListener(TestListener listener) { fListeners.removeElement(listener); } /** * Returns a copy of the listeners. * 返回一个观察者集合的拷贝,当然是为了防止对观察者集合的非法方式操作 * 可以看到所有使用观察者集合的地方都通过它 */ private synchronized Vector cloneListeners() { return (Vector)fListeners.clone(); } /** * Informs the result that a test was completed. */ public void endTest(Test test) { for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).endTest(test); } } //省略无关代码 .... }
在junit中是通过TestRunner来将观察者的各角色建立真正联系的。
public class TestRunner extends BaseTestRunner { private ResultPrinter fPrinter; public TestRunner(ResultPrinter printer) { fPrinter= printer; } public TestResult doRun(Test suite, boolean wait) { TestResult result= createTestResult(); // 在此处注册的 result.addListener(fPrinter); long startTime= System.currentTimeMillis(); suite.run(result); long endTime= System.currentTimeMillis(); long runTime= endTime-startTime; fPrinter.print(result, runTime); pause(wait); return result; } }
引用
https://blog.csdn.net/ai92/article/details/375691
https://blog.csdn.net/swengineer/article/details/6268244