设计模式--观察者模式
1. 概述
有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
2. 解决的问题
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
3. 模式中的角色
3.1 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
3.2 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3.3 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
3.4 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
4. 模式解读
4.1 观察者模式的代码
1 /// <summary> 2 /// 抽象主题类 3 /// </summary> 4 public abstract class Subject 5 { 6 private IList<Observer> observers = new List<Observer>(); 7 8 /// <summary> 9 /// 增加观察者 10 /// </summary> 11 /// <param name="observer"></param> 12 public void Attach(Observer observer) 13 { 14 observers.Add(observer); 15 } 16 17 /// <summary> 18 /// 移除观察者 19 /// </summary> 20 /// <param name="observer"></param> 21 public void Detach(Observer observer) 22 { 23 observers.Remove(observer); 24 } 25 26 /// <summary> 27 /// 向观察者(们)发出通知 28 /// </summary> 29 public void Notify() 30 { 31 foreach (Observer o in observers) 32 { 33 o.Update(); 34 } 35 } 36 } 37 38 /// <summary> 39 /// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己 40 /// </summary> 41 public abstract class Observer 42 { 43 public abstract void Update(); 44 } 45 46 /// <summary> 47 /// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。 48 /// </summary> 49 public class ConcreteSubject : Subject 50 { 51 private string subjectState; 52 53 /// <summary> 54 /// 具体观察者的状态 55 /// </summary> 56 public string SubjectState 57 { 58 get { return subjectState; } 59 set { subjectState = value; } 60 } 61 } 62 63 /// <summary> 64 /// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调 65 /// </summary> 66 public class ConcreteObserver : Observer 67 { 68 private string observerState; 69 private string name; 70 private ConcreteSubject subject; 71 72 /// <summary> 73 /// 具体观察者用一个具体主题来实现 74 /// </summary> 75 public ConcreteSubject Subject 76 { 77 get { return subject; } 78 set { subject = value; } 79 } 80 81 public ConcreteObserver(ConcreteSubject subject, string name) 82 { 83 this.subject = subject; 84 this.name = name; 85 } 86 87 /// <summary> 88 /// 实现抽象观察者中的更新操作 89 /// </summary> 90 public override void Update() 91 { 92 observerState = subject.SubjectState; 93 Console.WriteLine("The observer's state of {0} is {1}", name, observerState); 94 } 95 }
4.2 客户端代码
公司的一个需求,具体是,我的一个类变化了,我需要了解到这个类的变化,并且得到他的id,和模块名称(在本demo中没有体现),那么就用到了观察者模式!
首先,我们的业务类有一个顶层的接口,所有的业务类都实现了这个接口
package com.sun.Observer; import java.io.Serializable; public interface Entity<PK extends Serializable> extends Serializable { void setId(PK id); PK getId(); }
定义一个具体的业务类,方便测试
package com.sun.Observer; public class Student implements Entity<String> { private static final long serialVersionUID = 1L; private String id; private String name; private Integer age; @Override public void setId(String id) { this.id = id; } @Override public String getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
定义一个观察者
package com.sun.Observer; import java.util.Observable; import java.util.Observer; public class TstObServer implements Observer{ @Override public void update(Observable observ, java.lang.Object o) { EntityEventBlock eeb = (EntityEventBlock) observ; System.out.println("捕获业务对象变动数 = "+ eeb.getChangeEvents().size()); for (EntityChangeEvent event : eeb.getChangeEvents()) { System.out.println("entityCls:[" + event.getEntityCls() + "]" + ",id:[" + event.getId() + "]" + ",变动类型:[" + (event.getType() == EntityChangeEvent.TYPE_ADD ? "新增" : event.getType() == EntityChangeEvent.TYPE_UPDATE ? "更新" : event.getType() == EntityChangeEvent.TYPE_DELETE ? "删除" : "") + "]"); } } }
监听实体变化的辅助类
package com.sun.Observer; import java.io.Serializable; import org.apache.commons.lang3.StringUtils; public class EntityChangeEvent { public static final int TYPE_ADD = 1; public static final int TYPE_UPDATE = 2; public static final int TYPE_DELETE = 3; private Class<?> entityCls; private Serializable id; private int type; public EntityChangeEvent(Class<?> entityCls, Serializable id, int type) { this.id = id; this.type = type; this.entityCls = entityCls; } public Class<?> getEntityCls() { return entityCls; } public Serializable getId() { return id; } public String getIdStr() { return id != null ? id.toString() : null; } public void setId(Serializable id) { this.id = id; } public int getType() { return type; } @Override public boolean equals(Object obj) { if (!EntityChangeEvent.class.isInstance(obj)) { return false; } EntityChangeEvent otherObj = (EntityChangeEvent) obj; return (StringUtils.equals(getIdStr(), otherObj.getIdStr())); } @Override public int hashCode() { if (id != null) { return id.hashCode(); } return super.hashCode(); } }
通知主题
1 package com.sun.Observer; 2 3 import java.io.Serializable; 4 import java.util.ArrayList; 5 import java.util.List; 6 import java.util.Observable; 7 import java.util.Observer; 8 9 public class EntityEventBlock extends Observable { 10 private List<EntityChangeEvent> changeEvents = new ArrayList<EntityChangeEvent>(); 11 12 public void setObservers(List<Observer> observers) {//这里可以注入进来observer 13 for (Observer observer : observers) { 14 this.addObserver(observer); 15 } 16 } 17 18 public static synchronized EntityEventBlock instance() { 19 EntityEventBlock eventBlock = new EntityEventBlock();// from httpSession 20 return eventBlock; 21 } 22 23 public void makeDelEvent(Class entityCls, Serializable id) { 24 makeChangeEvent(entityCls, id, EntityChangeEvent.TYPE_DELETE); 25 } 26 27 public void makeAddEvent(Class entityCls, Serializable id) { 28 makeChangeEvent(entityCls, id, EntityChangeEvent.TYPE_ADD); 29 } 30 31 public void makeUpdateEvent(Class entityCls, Serializable id) { 32 makeChangeEvent(entityCls, id, EntityChangeEvent.TYPE_UPDATE); 33 } 34 35 private void makeChangeEvent(Class entityCls, Serializable id, int changeType) { 36 EntityChangeEvent e = new EntityChangeEvent(entityCls, id, changeType); 37 if (changeEvents.contains(e)) { 38 changeEvents.remove(e); 39 } 40 changeEvents.add(e); 41 this.setChanged(); 42 this.notifyObservers(); 43 } 44 45 public List<EntityChangeEvent> getChangeEvents() { 46 return changeEvents; 47 } 48 49 public void setChangeEvents(List<EntityChangeEvent> changeEvents) { 50 this.changeEvents = changeEvents; 51 } 52 }
测试
1 package com.sun.Observer; 2 3 import java.util.Observer; 4 import java.util.UUID; 5 6 7 public class ObserverDemo { 8 private static EntityEventBlock e = EntityEventBlock.instance(); 9 static { 10 Observer o = new TstObServer(); 11 e.addObserver(o); 12 } 13 14 public static void main(String[] args) { 15 16 Student s1 = new Student(); 17 s1.setId(UUID.randomUUID().toString()); 18 add(s1); 19 Student s2 = new Student(); 20 s2.setId(UUID.randomUUID().toString()); 21 add(s2); 22 23 } 24 25 static void update(Entity entity) { 26 e.makeUpdateEvent(entity.getClass(), entity.getId()); 27 28 } 29 30 static void add(Entity entity) { 31 e.makeAddEvent(entity.getClass(), entity.getId()); 32 } 33 34 static void delete(Entity entity) { 35 e.makeDelEvent(entity.getClass(), entity.getId()); 36 } 37 }