简介
前面的博客https://goo.gl/DFOz50中已经介绍过基本的观察者模式的代码实现,在实际应用中,我们往往希望代码更加简洁,同时也希望能与现有的框架,比如Spring,结合起来。下面介绍如何做抽象。
简单抽象
前面介绍过观察者模式有Subject,Observer,Client几种角色。在使用面向对象的时候Subject 和Observer都可以被抽象成接口,所以从原来的三种角色可以进化为6个角色。
(1) Subject : 被监控对象,抽象以后我们叫做BUS(总线,所有对被监控对象的操作都由它完成);
(2) concreteSubject:具体的被监控对象
(3)Observer(Listener):观察者
(4)concreteObserver:具体的观察者
(5)event : 监控对象和被监控对象交互时用到的消息
下面的类图用来解释新的观察者模式:
Note:
(1) 图中引入了泛型T作为观察者,从而使得每一个Bus的具体实现对应一个Listener接口,这样一个Bus最终只对应到一类事件;
(2)Listener和Bus之间交互使用一个单独的类Event实现;
(3)ExecutorService的引入使得监听器的响应与主线程异步进行,提升效率。
如果对上面的图进一步抽象的话就编程了下面这样:
代码实现
Step 1
创建AbstractBus
public abstract class BaseBus<T> {
private final List<T> listeners = new CopyOnWriteArrayList<T>();
private final ExecutorService executorService;
protected BaseBus(ExecutorService executorService) {
this.executorService = executorService;
}
public void iterate(final ListenerCallback<T> callback){
for(final T t:listeners){
this.executorService.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
callback.doWithListener(t);
return true;
}
});
}
}
public interface ListenerCallback<T> {
Object doWithListener(T t);
}
public boolean addListener(T listener) {
return this.listeners.add(listener);
}
public List<T> getListeners() {
return listeners;
}
public void setListeners(List<T> listeners) {
this.listeners.addAll(listeners);
}
}
Step 2
创建AbstractBus的具体实现:
public class ProfileChangeBus extends BaseBus<ProfileChangeListener> {
public ProfileChangeBus(){
super(new ThreadPoolExecutor(
2, 10,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()));
}
public void fireCreate(final ProfileChangeEvent event) {
event.setType(0);
iterate(new ListenerCallback<ProfileChangeListener>() {
@Override
public Object doWithListener(ProfileChangeListener profileChangeListener) {
profileChangeListener.onCreate(event);
return true;
}
});
}
public void fireUpdate(final ProfileChangeEvent event) {
event.setType(0);
this.iterate(new ListenerCallback<ProfileChangeListener>() {
@Override
public Object doWithListener(ProfileChangeListener profileChangeListener) {
profileChangeListener.onUpdate(event);
return true;
}
});
}
public void fireDelete(final ProfileChangeEvent event) {
event.setType(0);
this.iterate(new ListenerCallback<ProfileChangeListener>() {
@Override
public Object doWithListener(ProfileChangeListener profileChangeListener) {
profileChangeListener.onDelete(event);
return true;
}
});
}
}
Step 3
创建Listener
public interface ProfileChangeListener {
void onCreate(ProfileChangeEvent profileChangeEvent);
void onUpdate(ProfileChangeEvent profileChangeEvent);
void onDelete(ProfileChangeEvent profileChangeEvent);
}
Step 4
创建Listener的具体实现,这里有3个实现类:
(1)
public class ProfileChangeListenerAdapter implements ProfileChangeListener {
@Override
public void onCreate(ProfileChangeEvent profileChangeEvent) {
System.out.println("trigger create");
}
@Override
public void onUpdate(ProfileChangeEvent profileChangeEvent) {
System.out.println("trigger update");
}
@Override
public void onDelete(ProfileChangeEvent profileChangeEvent) {
System.out.println("trigger delete");
}
}
(2)
public class ProfileChangeListenerAdapter4MQ extends ProfileChangeListenerAdapter {
@Override
public void onCreate(ProfileChangeEvent profileChangeEvent) {
System.out.println("mq trigger create");
}
@Override
public void onUpdate(ProfileChangeEvent profileChangeEvent) {
System.out.println("mq trigger update");
}
@Override
public void onDelete(ProfileChangeEvent profileChangeEvent) {
System.out.println("mq trigger delete");
}
}
(3)
public class ProfileChangeListener4DB implements ProfileChangeListener{
@Override
public void onCreate(ProfileChangeEvent profileChangeEvent) {
System.out.println("db trigger create");
}
@Override
public void onUpdate(ProfileChangeEvent profileChangeEvent) {
System.out.println("db trigger create");
}
@Override
public void onDelete(ProfileChangeEvent profileChangeEvent) {
System.out.println("db trigger create");
}
}
Step 5
创建Event
public class ProfileChangeEvent {
private int type;
private String message;
public ProfileChangeEvent(int type, String message){
this.type = type;
this.message = message;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Step 6
将Listener注入到ConcreteBus
<bean id="profileChangeBus" class="designpattern.observer.ProfileChangeBus">
<property name="listeners">
<list>
<bean class="designpattern.observer.ProfileChangeListener4DB" />
<bean class="designpattern.observer.ProfileChangeListenerAdapter4MQ"/>
</list>
</property>
</bean>
Step 7
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:config/*.xml"
})
public class ObserverPatternTest {
@Autowired
private ProfileChangeBus profileChangeBus;
@Test
public void test(){
profileChangeBus.fireCreate(new ProfileChangeEvent(1, "1"));
}
}