观察者模式结构图:
从上图中可以看到观察者模式需要4个角色:
1.Observer:抽象观察者。
2.ConcreteObserver:具体观察者。
3.Subject:抽象通知者。
4.ConcreteSubject:具体通知者。
这里我们用上班玩手机来举例:有几个同事每天在公司的状态为“玩手机”,然后为了不给老板发现,安排了一个靠近大门的同事当他们的通知者,当老板走入大门的时候,这个同事就要马上通知他们,他们会更新状态为“工作”。假如这个同事没有及时通知他们,那么通知者就会变成老板,老板当场抓获他们的状态为“玩手机”,同时还要当场批评。
下面我们通过代码来进行实现:
1.定义抽象观察者同事Observer,里面只有一个方法update用来更新状态:这里定义接口的意义在于遵循“开放--封闭原则”,如果有新的偷偷看电影的同事,也可以实现接口,保证对观察者对象的内部一致性。
public interface Observer { void update(String state); }
2.定义具体的观察者同事ConcreteObserver:
public class ConcreteObserver implements Observer { private String state = "玩手机"; //默认在玩手机 @Override public void update(String state) { //由坐在靠窗位置的同事进行通知,通知后马上修改状态。 this.state = state; } }
3.定义抽象通知者同事:这里接口的定义同样是为了满足"开放—封闭原则",因为通知者有可能是靠窗的同事,也可能是被老板给抓了现场。
public interface Subject { void add(Observer observer); //添加通知的同事 void remove(Observer observer); //移除通知的同事 void notice(String notice); //通知同事 }
4.定义具体的通知者同事:这里只定义了通知者同事,没有定义通知者老板,老板类似,只不过会多一个扣除工资的操作。
public class ConcreteSubject implements Subject { private List<Observer> list = new ArrayList<>(); @Override public void add(Observer observer) { list.add(observer); } @Override public void remove(Observer observer) { list.remove(observer); } @Override public void notice(String notice) { for (Observer observer : list) { observer.update("工作!"); } } }
5.客户端:实际流程开始了
public class Main8 { public static void main(String[] args) { Subject subject1 = new ConcreteSubject(); //通知者同事 Observer observer1 = new ConcreteObserver(); //观察者同事1 Observer observer2 = new ConcreteObserver(); //观察者同事2 Observer observer3 = new ConcreteObserver(); //观察者同事3 //将同事添加到通知对象里面来 subject1.add(observer1); subject1.add(observer2); subject1.add(observer3); // 老板来了,赶紧通知工作! subject1.notice("工作!"); } }
特点:
将一个复杂系统分成几个小模块后,需要在这几个模块中保持一致性,但是又不能让他们进行紧耦合。此时可以通过观察者模式,又称订阅—发布模式,令这几个模块都订阅某一事件,当事件发生后,通知模块会对订阅了这一事件的模块分别进行通知,以让他们保持一致性。