GOF设计模式之OBSERVER(观察者)

来源:互联网 发布:金钟国力量数据 编辑:程序博客网 时间:2024/04/30 19:02

概述

本文将和读者一起来理解GOF设计模式之OBSERVER(观察者)。同样,本文将用JAVA对GOF中的示例代码改些,同时附上测试用例。

模式结构

GOF对观察者的模式结构描述如
这里写图片描述
观察者要完成的任务是,当Subject执行Notify的时候,将触发Observer.Update。实现很直白,维护一个o: Observer的数组用以保存Observer,在Notify方法中遍历o: Observer,调用Update方法。
这么做的好处在于Observer和Subject的功能拆分得很独立。Subject不用管Observer的处理逻辑,只需要调用Notify通知Observer对象即可。而Observer将在Update中执行触发相应的处理逻辑。从而Subject和Observer完成了一定程度的解耦。
GOF列举了11中行为模式,其中观察者模式又是里头应用广泛的一个。PHP中,观察者模式单独被提出作为SPL类库使用,足以可见其常用型。

代码示例

这里写图片描述
AnalogClock与DigitalClock作为两种时钟,将观察定时器任务对象SubjectTimerTask,当SubjectTimerTask调用Run方法时将触发其Update方法。代码如下:

package gof.observer;public class AnalogClock extends Observer{    protected SubjectTimerTask timerSubject;    public AnalogClock(SubjectTimerTask timerSubject) {        this.timerSubject = timerSubject;        this.timerSubject.subject.Attach(this);    }    protected void finalize() {        this.timerSubject.subject.Detach(this);    }    public void Update(Subject theChangedSubject) {        if(this.timerSubject.subject.equals(theChangedSubject)) {            this.Draw();        }    }    public void Draw() {        System.out.println("draw in AnalogClock");    }}
package gof.observer;public class DigitalClock extends Observer{    protected SubjectTimerTask timerSubject;    public DigitalClock(SubjectTimerTask subject) {        this.timerSubject = subject;        this.timerSubject.subject.Attach(this);    }    protected void finalize() {        this.timerSubject.subject.Detach(this);    }    public void Update(Subject theChangedSubject) {         if(this.timerSubject.subject.equals(theChangedSubject)) {            this.Draw();        }    }    public void Draw() {        System.out.println("draw in Digital Clock");    }}
package gof.observer;public abstract class Observer {    public abstract void Update(Subject subject);}
package gof.observer;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class Subject {    protected List<Observer> observers = new ArrayList<Observer>();    public void Attach(Observer observer) {        this.observers.add(observer);    }    public void Detach(Observer observer) {        Iterator<Observer> iterator = this.observers.iterator();        if (iterator.hasNext()) {            Observer next = iterator.next();            if (next.equals(observer)) {                iterator.remove();            }        }    }    public void Notify() {        Iterator<Observer> iterator = this.observers.iterator();        while(iterator.hasNext()) {            iterator.next().Update(this);        }    }}
package gof.observer;public class SubjectTimerTask {    Subject subject;    public SubjectTimerTask(Subject subject) {        this.subject = subject;    }    public void run() {        this.subject.Notify();    }}

测试用例:

package gof.observer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScanpublic class ObserverConfig {    @Bean    public Subject subject() {        return new Subject();    }    @Bean    public SubjectTimerTask subjectTimerTask(Subject subject) {        return new SubjectTimerTask(subject);    }    @Bean    public AnalogClock analogClock(SubjectTimerTask timerSubject) {        return new AnalogClock(timerSubject);    }    @Bean    public DigitalClock digitalClock(SubjectTimerTask timerSubject) {        return new DigitalClock(timerSubject);    }}
package gof.observer;import static org.junit.Assert.*;import org.junit.Rule;import org.junit.Test;import org.junit.contrib.java.lang.system.StandardOutputStreamLog;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import org.springframework.test.context.support.AnnotationConfigContextLoader;@ContextConfiguration(classes=ObserverConfig.class,loader=AnnotationConfigContextLoader.class)@RunWith(SpringJUnit4ClassRunner.class)public class ObserverTest {    @Rule    public final StandardOutputStreamLog log = new StandardOutputStreamLog();    @Autowired    protected ApplicationContext context;    @Autowired    protected SubjectTimerTask task;    @Autowired    protected AnalogClock aclock;    @Autowired    protected DigitalClock dclock;    protected String newLineMark;    @Autowired    public void setNewLineMark() {        this.newLineMark = System.getProperty("line.separator");    }    @Test    public void draw() {        this.task.run();        assertEquals("draw in AnalogClock" + this.newLineMark                + "draw in Digital Clock" + this.newLineMark, this.log.getLog());    }}
0 0
原创粉丝点击