JAVA设计模式——观察者模式实战

      观察者模式也叫发布订阅模式,这种模式在我们日常开发中很是常见,以不同的形式存在于我们的项目中,消息对列就是一个很好的例子。

       java中将这种模式封装了一下,将其内置在jdk中,java.util.Observable,java.util.Observer,

      java自身的观察者模式实现还是较为简略,本文主要讲google的guava中实现的观察者模式的使用,以及碰到的一些问题,故转载以下内容,

Java内置的观察者模式, 是通过继承父类, 实现观察者模式的几个主要函数:

Observerable(可被观察的): 是一个父类(class),addObserver(), 添加观察者; deleteObserver(), 删除观察者; 

notifyObservers(), 通知观察者;setChanged(), 确认更改;

Observer(观察者): 是一个接口(interface), update(), 更新观察者数据;

setChanged()->notifyObservers(), 必须要先使用setChanged(), 再使用notifyObservers(), 即先确认提交, 再通知观察者;

观察者的更新接口update(Observerable o, Object arg), 即可以使用推(push), 也可以使用拉(pull);

如果notifyObservers(arg), 传递参数, 则为推(push)的方法, 如果没有参数, 则为拉(pull)的方式, 即使用get()方法获取;

观察者的通知(notify)顺序是先入后出的模式.

————————————————

版权声明:本文为CSDN博主「SpikeKing」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/caroline_wendy/article/details/26601659

 

guava使用说明:

    导入maven依赖:

<dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>20.0</version>
</dependency>

    发布类PublishEventUtil :

package com.zhou.cfets.common.event;

import com.google.common.eventbus.EventBus;

public class PublishEventUtil {

	private final static EventBus EVENT_BUS = new EventBus();

	/**
	 * 注册一个对象
	 * 
	 * @param o
	 */
	public static void register(Object o) {
		EVENT_BUS.register(o);
	}

	/**
	 * 取消注册
	 * 
	 * @param o
	 */
	public static void unregister(Object o) {
		EVENT_BUS.unregister(o);
	}

	/**
	 * 发布事件
	 * 
	 * @param event session logon,logout,onerror
	 */
	public static void publishCodeEvent(int event) {
		EVENT_BUS.post(event);
	}

	/**
	 * 发布事件
	 * 
	 * @param event session logon,logout,onerror
	 */
	public static void publishEvent(Object event) {
		EVENT_BUS.post(event);
	}
}

    消费基类AbstractSubscribe :

package com.zhou.cfets.common.event;

import com.google.common.eventbus.DeadEvent;
import com.google.common.eventbus.Subscribe;

public abstract class AbstractSubscribe {

    @Subscribe
    public abstract void onEvent(Integer event);
    
    @Subscribe
    public abstract void onEvent(DeadEvent event);
    
}

(问题一:细心地朋友可能看到我发布的类,发布的事件是int,订阅的却是Integer的类型,这个问题稍后再说明) 

   启动测试类:

package com.zhou.cfets.common.event;

import com.google.common.eventbus.DeadEvent;

public class PublishEventTest {

	public static void main(String[] args) throws InterruptedException {
		
		PublishEventUtil.register(new AbstractSubscribe() {
			
			@Override
			public void onEvent(DeadEvent event) {
				// TODO Auto-generated method stub
				System.out.println("DeadEvent " + event );
			}
			@Override
			public void onEvent(Integer event) {
				// TODO Auto-generated method stub
				System.out.println("Integer " + event );
			}
		});
		
		PublishEventUtil.publishCodeEvent(111);
		PublishEventUtil.publishEvent("DeadEvent");
		
		Thread.sleep(5000L);
	}

}

 运行结果:

 

到此示例结束。

现在我们回归到问题一,如果在消费消息的时候将消费基类AbstractSubscribe的OnEvent的方法Integer类型改为int类型的话,是不能消费事件的,有疑惑的朋友可以试一下,那么为什么呢?

我们查看guava的com.google.common.eventbus.EventBus.post源码发现,post接收的是一个Object的对象,那么java在转换的的时候就将int类型的自动装箱成了Intger类型,

/**
   * Posts an event to all registered subscribers. This method will return successfully after the
   * event has been posted to all subscribers, and regardless of any exceptions thrown by
   * subscribers.
   *
   * <p>If no subscribers have been subscribed for {@code event}'s class, and {@code event} is not
   * already a {@link DeadEvent}, it will be wrapped in a DeadEvent and reposted.
   *
   * @param event event to post.
   */
  public void post(Object event) {
    //通过event的类型去获取订阅类,找到正常消费消息,如果没有读到则发布DeadEvent事件
    Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
    if (eventSubscribers.hasNext()) {
      dispatcher.dispatch(event, eventSubscribers);
    } else if (!(event instanceof DeadEvent)) {
      // the event had no subscribers and was not itself a DeadEvent
      post(new DeadEvent(this, event));
    }
  }


 /**
   * Gets an iterator representing an immutable snapshot of all subscribers to the given event at
   * the time this method is called.
   */
  Iterator<Subscriber> getSubscribers(Object event) {
     //这里通过Object的getClass获取订阅对象的运行时对象,进而获取相关的订阅类
    ImmutableSet<Class<?>> eventTypes = flattenHierarchy(event.getClass());

    List<Iterator<Subscriber>> subscriberIterators =
        Lists.newArrayListWithCapacity(eventTypes.size());

    for (Class<?> eventType : eventTypes) {
      CopyOnWriteArraySet<Subscriber> eventSubscribers = subscribers.get(eventType);
      if (eventSubscribers != null) {
        // eager no-copy snapshot
        subscriberIterators.add(eventSubscribers.iterator());
      }
    }

    return Iterators.concat(subscriberIterators.iterator());
  }


自动装箱机制我们可以做一个实验,如下,我们得到int却是变成了Integer对象 

public class Test {
private static void getIntClass(Object a) {
		System.out.println(a.getClass());
	}
	public static void main(String[] args) {
		getIntClass(1);
    }
}

如果错误还请指正,谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值