设计模式实战应用之二:观察者模式

        观察者模式的定义
        观察者模式是应用最普遍的设计模式之一。著名的 MVC 模式就是观察者模式的应用之一;高性能网络应用框架 MINA 中的 事件处理器也是观察者模式的应用之一,一旦有 I/O 事件,所有注册的 IoHandler 对象会被通知到,我们可以通过对这个接口的自定义扩展以实现相应业务处理;流媒体服务 Wowza Streaming Engine 的 插件模块扩展开发也正是利用到了观察者模式,用户通过自定义模块对比如  com.wowza.wms.stream.IMediaStreamActionNotify 等接口的实现,可以捕捉到自己所关心的流的一系列事件,进而就可以 对特定直播/点播频道进行监控了。Gof 把观察者模式归类到对象行为型模式,《 设计模式:可复用面向对象软件的基础》对观察者模式做出了明确的定义:“ Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.” 翻译过来就是:“ 定义了一些对象之间的一对多依赖关系,这样子当一个对象的状态发生变化时,所有依赖于这个对象的对象都会得到通知,并被自动更新”。
        why 观察者模式?
        把系统设计成一些互相合作的类有一个常见的弊端:需要维护相关对象之间的一致性。为了维护一致性而使各类紧密耦合,大大降低了模块的可复用性,这是我们不愿意看到的。
        观察者模式的使用场合
  • 当一个抽象模型具有一方依赖于另一方的两方面时,将它们封装在独立的对象中可以让你对它们独立地改变和复用。
  • 当对于一个对象的改变需要同时改变其他对象,而且你不知道有多少对象需要改变。
  • 当一个对象需要通知其他对象,又不能假定其他对象是谁,换句话说,你不希望这些对象紧密地耦合在一起。
        《多线程高效读取缓冲区数据》需求
        本文示例摒弃了那些枯燥无味、与我们项目毫无关联的鸭子啊报社啊葡萄园之类的,同时也因为抄来抄去而被用烂了的无聊话题,采用的是 CSDN 网友项目实战中真实遇到而提出来的一个问题作为案例进行分析。让我们切实感受设计模式带来的好处,领略设计模式的真正的威力,而不只是用来玩理论、侃大山。
        这个是网友 xgPaul 发帖提出的一个讨论。标题是《如何实现多线程高效的读取一块缓冲区中的数据???》帖子链接是: http://bbs.csdn.net/topics/390658695
        帖子正文描述如下:
        一条线程不断的对一块内存缓冲区进行写数据,同时几十条线程(几百个对象)要从该缓冲区中读取数据。这一过程如何实现高效与数据同步。(使用锁同步效率太低)
        《多线程高效读取缓冲区数据》分析
        xgPaul 遇到的这个问题,比较类似于上海抢拍车牌号的场景:一条线程不断地对当前价格进行刷新,同时几十条线程(几百个对象)对当前价格进行读取监控。用观察者模式效率比较好,可以解决由于线程竞争、加锁而带来的效率问题。把读数据的线程归为观察者,主题是缓冲区数据。一旦数据有更新,主题向观察者推送更新数据,这样推数据的做法效率很高。缓冲区做成主题,每个观察者都有一份自己关心的主题数据的本地备份,如果主题没有推数据过来,本地备份就是最新数据。当然,这么干稍耗空间,但是却换得多线程环境中效率上的大幅度提升,这就是所谓的用空间换时间。
        java.lang.ThreadLocal 就是这种原理的一个实现。
        《多线程高效读取缓冲区数据》类设计
        本文重在讲解模式,所以仅以一个 int 类型的数据 onlinePlayersNum 模拟缓冲区数据。两个发布板,一个公开发布板一个内部发布板作为观察者。
        由 BufferData 对象向两个发布板推数据,后者不需要去前者查询数据,只需要查询自己的状态是否改变以决定是否更新发布。具体类图设计如下:
观察者模式类图
        《多线程高效读取缓冲区数据》时序图
观察者模式时序图
        《多线程高效读取缓冲区数据》源码实现
        《 设计模式:可复用面向对象软件的基础》的观察者模式中的 Subject 角色,在本文中是为 Subject 接口,源码:
package com.defonds.buffer;

public interface Subject {
	public void registerObserver(Observer observer);
	public void removeObserver(Observer observer);
	public void notifyObservers();
}

        《 设计模式:可复用面向对象软件的基础》观察者模式中的 Observer 角色,在本文中是为 Observer 接口,源码:
package com.defonds.buffer;

public interface Observer {
	public void update(int onlineNum);
}

        《 设计模式:可复用面向对象软件的基础》观察者模式中的 ConcreteSubject 角色,在本文中是为 BufferData 类,源码:
package com.defonds.buffer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class BufferData implements Subject {
	private int onlinePlayersNum = 0; // store online players num
	private List<Observer> observers = new ArrayList<Observer>(); // refer to all observers
	
	@Override
	public void registerObserver(Observer observer) {
		this.observers.add(observer); // add one observer
		
	}

	@Override
	public void removeObserver(Observer observer) {
		int i = this.observers.indexOf(observer);
		if (i >= 0) {
			this.observers.remove(i);
		}

	}

	@Override
	public void notifyObservers() {
		Iterator<Observer> iterator = this.observers.iterator();
		while (iterator.hasNext()) {
			iterator.next().update(this.onlinePlayersNum);
		}
	}

	public void setOnlinePlayersNum(int onlinePlayersNum) {
		this.onlinePlayersNum = onlinePlayersNum;
		this.notifyObservers();
	}
	
	

}

        《 设计模式:可复用面向对象软件的基础》观察者模式中的 ConcreteObserver 角色之一,在本文中是为 PublicDisplay 类,源码:
package com.defonds.buffer;

public class PublicDisplay extends Thread implements Observer, Display {
	private int onlineNum;
	private boolean changed = false;

	@Override
	public void update(int onlineNum) {
		this.onlineNum = onlineNum;
		this.changed = true;
	}
	
	@Override
	public void display() {
		System.out.println("The current number of players online is : " + this.onlineNum);
	}

	@Override
	public void run() {
		while (this.changed) {
			this.display();
			this.changed = false;
		}
	}
}

        《设计模式:可复用面向对象软件的基础》观察者模式中的 ConcreteObserver 角色之二,在本文中是为 InternalDisplay 类,源码:

package com.defonds.buffer;

public class InternalDisplay extends Thread implements Observer, Display {
	private int oldNum = 0;
	private int onlineNum = 0;
	private boolean changed = false;

	@Override
	public void update(int onlineNum) {
		this.oldNum = this.onlineNum;
		this.onlineNum = onlineNum;
		this.changed = true;
	}
	
	@Override
	public void display() {
		System.out.println("The current number of players online is : " + this.onlineNum);
		if(this.onlineNum > this.oldNum) {
			System.out.println("The number of online upward");
		} else {
			System.out.println("The number of online decline");
		}
	}
	
	@Override
	public void run() {
		while (this.changed) {
			this.display();
			this.changed = false;
		}
	}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值