设计模式~观察者模式

来源:互联网 发布:纽芬兰纪念大学知乎 编辑:程序博客网 时间:2024/05/21 06:28

观察者模式 Observer

  观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

  这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。

 

观察者模式的组成

  抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。

  抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。

  具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。

  具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。

 

程序实例

  通过程序实例来说明观察者模式:

  首先定义抽象的观察者:

复制代码
//抽象观察者角色public interface Watcher{    public void update(String str);}
复制代码

  然后定义抽象的主题角色,即抽象的被观察者,在其中声明方法(添加、移除观察者,通知观察者):

复制代码
//抽象主题角色,watched:被观察public interface Watched{    public void addWatcher(Watcher watcher);    public void removeWatcher(Watcher watcher);    public void notifyWatchers(String str);}
复制代码

  然后定义具体的观察者:

复制代码
public class ConcreteWatcher implements Watcher{    @Override    public void update(String str)    {        System.out.println(str);    }}
复制代码

  之后是具体的主题角色: 

复制代码
import java.util.ArrayList;import java.util.List;public class ConcreteWatched implements Watched{    // 存放观察者    private List<Watcher> list = new ArrayList<Watcher>();    @Override    public void addWatcher(Watcher watcher)    {        list.add(watcher);    }    @Override    public void removeWatcher(Watcher watcher)    {        list.remove(watcher);    }    @Override    public void notifyWatchers(String str)    {        // 自动调用实际上是主题进行调用的        for (Watcher watcher : list)        {            watcher.update(str);        }    }}
复制代码

  编写测试类:

复制代码
public class Test{    public static void main(String[] args)    {        Watched girl = new ConcreteWatched();                Watcher watcher1 = new ConcreteWatcher();        Watcher watcher2 = new ConcreteWatcher();        Watcher watcher3 = new ConcreteWatcher();                girl.addWatcher(watcher1);        girl.addWatcher(watcher2);        girl.addWatcher(watcher3);                girl.notifyWatchers("开心");    }}
复制代码

 

实际应用在Java语言中:

EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。

  Observer模式是比较常用的设计模式之一,虽然有时候在具体代码里,它不一定叫这个名字,比如改头换面叫个Listener,但模式就是这个模式。手工实现一个Observer也不是多复杂的一件事,只是因为这个设计模式实在太常用了,Java就把它放到了JDK里面:Observable和Observer,从JDK 1.0里,它们就一直在那里。从某种程度上说,它简化了Observer模式的开发,至少我们不用再手工维护自己的Observer列表了。不过,如前所述,JDK里的Observer从1.0就在那里了,直到Java 7,它都没有什么改变,就连通知的参数还是Object类型。要知道,Java 5就已经泛型了。Java 5是一次大规模的语法调整,许多程序库从那开始重新设计了API,使其更简洁易用。当然,那些不做应对的程序库,多半也就过时了。这也就是这里要讨论知识更新的原因所在。今天,对于普通的应用,如果要使用Observer模式该如何做呢?答案是Guava的EventBus。

  EventBus基本用法:

  使用Guava之后, 如果要订阅消息, 就不用再继承指定的接口, 只需要在指定的方法上加上@Subscribe注解即可。代码如下:

public class TestEvent {    private final int message;    public TestEvent(int message) {                this.message = message;        System.out.println("event message:"+message);    }    public int getMessage() {        return message;    }}

public class EventListener {    public int lastMessage = 0;    @Subscribe    public void listen(TestEvent event) {        lastMessage = event.getMessage();        System.out.println("Message:"+lastMessage);    }    public int getLastMessage() {              return lastMessage;    }}

public class TestEventBus {    @Test    public void testReceiveEvent() throws Exception {        EventBus eventBus = new EventBus("test");        EventListener listener = new EventListener();        eventBus.register(listener);        eventBus.post(new TestEvent(200));        eventBus.post(new TestEvent(300));        eventBus.post(new TestEvent(400));        System.out.println("LastMessage:"+listener.getLastMessage());        ;    }}

//输出信息event message:200Message:200event message:300Message:300event message:400Message:400LastMessage:400



在项目中的具体应用:

package com.creditcloud.creditmarket.local;
public interface 
NotificationsHandler {
    void run();
}


package com.creditcloud.creditmarket.local;
import com.creditcloud.creditmarket.constant.CreditMarketConstant;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
import javax.annotation.PostConstruct;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@LocalBean
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class EmailLocalExecutor {
    ExecutorService executorService;
    

    @PostConstruct
    public void init() {
        executorService = Executors.newFixedThreadPool(CreditMarketConstant.NOTIFICATION_THREADPOOL_SIZE);
    }


    @Subscribe
    @AllowConcurrentEvents
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void emailThreadPoolHandler(final 
NotificationsHandler handler) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                handler.run();
            }
        });
    }
}



appBean.getEmailEventBus().post( new NotificationsHandler() {
       @Override
       public void run() {
                  try {
                            //发送邮件:很高兴的通知您,您已预投标成功,中标总金额为%s,请在规定的时间内充值。
                            emailService.sendPreInvest(appBean.getClient(), email, name, amount);
                  } catch (Exception ex) {
                            logger.error("PreBid Email Sent to Investor Failed: email:{},userName:{}", email, name, ex);
                  }
       }
});

1 0
原创粉丝点击