Observer(观察者)模式的代码演示

关于什么是Observer(观察者)模式,它的原理是什么,我不擅长理论知识的说明,这里通过一个简单有趣的小例子来给大家演示,相信大家看完之后,就会很明白了。

现在假设:一个小孩子在睡觉,睡醒后要他父亲来喂他吃东西,用代码怎么实现?

用面向对象的思维来考虑,至少要定义两个类,一个小孩类,一个父亲类,ok,看第一种实现方式,看代码

package demo1;

/**
 * 第一种实现方式:让父亲主动的去观察小孩是否睡醒<br>
 * 定义一个父亲类,并实现Runnable接口,让这个父亲类每个一段时间就去观察一下小孩是否醒来
 * 定义一个小孩类,并实现Runnable接口,在run()方法中让小孩睡上一段时间,然后醒来
 * 
 * @author jerry
 * 
 * 
 */

/**
 * 小孩类
 */
class Child implements Runnable {
	// 是否起床的标志
	private boolean wakeup = false;

	public boolean isWakeup() {
		return wakeup;
	}

	public void setWakeup(boolean wakeup) {
		this.wakeup = wakeup;
	}

	// 起床
	public void wakenUp() {
		this.wakeup = true;
	}

	@Override
	public void run() {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 模拟小孩睡5秒后起床
		wakenUp();
	}

}

/**
 * 父亲类
 */
class Dad implements Runnable {
	Child c;

	public Dad(Child c) {
		super();
		this.c = c;
	}

	@Override
	public void run() {
		// 让父亲每个一秒就去看一下小孩是否睡醒
		while (!c.isWakeup()) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// 如果睡醒,就喂小孩吃饭
		feed(c);
	}

	private void feed(Child c) {
		System.out.println("喂小孩");
	}

}

public class Test1 {
	public static void main(String[] args) {
		Child c = new Child();
		new Thread(c).start();
		new Thread(new Dad(c)).start();
	}

}
这样去实现代码,有很多不足的地方,比如很明显的一个,父亲要重复去观察小孩是否睡醒,不能去干其他事情,比如看巴西世界杯 委屈


为了改进这个问题,我们再来看第二种实现方式,看代码

package demo2;

/**
 * 第二种实现方式:让小孩主动告知父亲,我睡醒,我要吃饭!<br>
 * 定义一个父亲类,提供一个喂小孩的方法<br>
 * 定义一个小孩类,并实现Runnable接口,在run()方法中让小孩睡上一段时间,然后醒来
 * 
 * @author jerry
 * 
 */

class Child implements Runnable {
	private Dad dad;

	public Child(Dad dad) {
		super();
		this.dad = dad;
	}

	public void wakenUp() {
		this.dad.feed(this);
	}

	@Override
	public void run() {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		wakenUp();
	}

}

class Dad {

	public void feed(Child c) {
		System.out.println("喂小孩");
	}

}

public class Test2 {
	public static void main(String[] args) {
		Dad dad = new Dad();
		Child c = new Child(dad);
		new Thread(c).start();
	}

}
这回只要屁孩没醒,父亲就可以去做他想做的事情,可是这样还是有个问题。如果小孩是在不同时间段睡醒来,父亲要做出不同的事件处理 可怜,就要在wakenUp里写大量的判断处理代码,然后调用父亲类中相应的处理方法,程序的可扩展性太差


为了改进这个问题,我们继续修改上边的代码,看第三种实现方式

package demo3;

/**
 * 第三种实现方式:再定义一个事件类,用于记录处理起床的各种属性<br>
 * 定义一个父亲类,提供一个处理小孩睡醒事件的方法<br>
 * 定义一个小孩类,并实现Runnable接口,在run()方法中让小孩睡上一段时间,然后醒来
 * 
 * @author jerry
 * 
 */

/**
 * 事件类,用于记录处理起床的各种属性
 */
class WakenUpEvent {
	private long time;// 起床事件
	private String loc;// 起床地点
	private Child source;// 事件源

	public WakenUpEvent(long time, String loc, Child source) {
		super();
		this.time = time;
		this.loc = loc;
		this.source = source;
	}

	public long getTime() {
		return time;
	}

	public void setTime(long time) {
		this.time = time;
	}

	public String getLoc() {
		return loc;
	}

	public void setLoc(String loc) {
		this.loc = loc;
	}

	public Child getSource() {
		return source;
	}

	public void setSource(Child source) {
		this.source = source;
	}
}

class Child implements Runnable {
	private Dad dad;

	public Child(Dad dad) {
		super();
		this.dad = dad;
	}

	public void wakenUp() {
		// 将起床的事件传给父亲类相应的处理方法
		this.dad.actionToWakenUp(new WakenUpEvent(System.currentTimeMillis(),
				"bed", this));
	}

	@Override
	public void run() {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		wakenUp();
	}

}

class Dad {

	public void actionToWakenUp(WakenUpEvent event) {
		System.out.println("time :" + event.getTime());
		System.out.println("loc :" + event.getLoc());
		// TODO 根据event里边的属性做不同的操作
	}

}

public class Test3 {
	public static void main(String[] args) {
		Dad dad = new Dad();
		Child c = new Child(dad);
		new Thread(c).start();
	}

}
这样代码看起来就爽多了,可是呢,屁孩有一天他不仅要他爸喂他,还要他妈抱他 抓狂。那就要在Child类中添加母亲的引用,重写wakenUp方法,程序扩展性还是太差


怎么办,进行修改实现方式,看第四种

package demo4;

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

/**
 * 第四种实现方式:使用bserver模式实现<br>
 * 定义一个起床事件监听器接口
 * 定义一个父亲类,继承起床事件监听器,监听小孩起床事件<br>
 * 定义一个母亲类,继承起床事件监听器,监听小孩起床事件<br>
 * 定义一个小孩类,并实现Runnable接口,在run()方法中让小孩睡上一段时间,然后醒来
 * 
 * @author jerry
 * 
 */

class WakenUpEvent {
	private long time;
	private String loc;
	private Child source;

	public WakenUpEvent(long time, String loc, Child source) {
		super();
		this.time = time;
		this.loc = loc;
		this.source = source;
	}

	public long getTime() {
		return time;
	}

	public void setTime(long time) {
		this.time = time;
	}

	public String getLoc() {
		return loc;
	}

	public void setLoc(String loc) {
		this.loc = loc;
	}

	public Child getSource() {
		return source;
	}

	public void setSource(Child source) {
		this.source = source;
	}
}

/**
 * 小孩子类
 */
class Child implements Runnable {
	// 起床事件监听器
	private List<WakenUpEventListener> listeners = new ArrayList<WakenUpEventListener>();

	// 注册起床事件的监听
	public void setOnWakenUpEventListener(WakenUpEventListener l) {
		listeners.add(l);
	}

	// 起床事件
	void wakenUp() {
		for (WakenUpEventListener listener : listeners) {
			// 回调起床事件监听器中的处理起床事件的方法
			listener.onWakenUp(new WakenUpEvent(System.currentTimeMillis(),
					"bed", this));
		}
	}

	@Override
	public void run() {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		wakenUp();
	}

}

/**
 * 父亲类,继承起床事件监听器,监听小孩起床事件
 */
class Dad implements WakenUpEventListener {

	@Override
	public void onWakenUp(WakenUpEvent event) {
		System.out.println("喂小孩");
	}

}

/**
 * 母亲类,继承起床事件监听器,监听小孩起床事件
 */
class Mother implements WakenUpEventListener {

	public void onWakenUp(WakenUpEvent event) {
		System.out.println("抱小孩");
	}

}

/**
 * 起床事件监听器接口
 */
interface WakenUpEventListener {
	public void onWakenUp(WakenUpEvent event);

}

public class Test4 {
	public static void main(String[] args) {
		Dad dad = new Dad();
		Mother mother = new Mother();
		Child c = new Child();
		c.setOnWakenUpEventListener(dad);
		c.setOnWakenUpEventListener(mother);
		new Thread(c).start();
	}

}

这就是观测者模式!比起第三种实现方式,非常明显的好处就是,当小孩需要更多的人相应他的起床事件的时候,我们只需要定义相应的类,然后去继承WakenUpEventListener接口并重写它里边的方法,就可以实现睡醒事件的监听,而不用去修改Child类中的代码。因此代码的可扩展性是很爽的 偷笑





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 C++ 观察者模式实现的代码示例: ``` #include <iostream> #include <vector> using namespace std; class Observer { public: virtual void update() = 0; }; class Subject { private: vector<Observer*> observers; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end()); } void notify() { for (Observer* observer : observers) { observer->update(); } } }; class ConcreteObserver1 : public Observer { public: void update() { cout << "ConcreteObserver1 received the update." << endl; } }; class ConcreteObserver2 : public Observer { public: void update() { cout << "ConcreteObserver2 received the update." << endl; } }; class ConcreteSubject : public Subject { public: void doSomething() { cout << "ConcreteSubject is doing something." << endl; notify(); } }; int main() { ConcreteSubject subject; ConcreteObserver1 observer1; ConcreteObserver2 observer2; subject.attach(&observer1); subject.attach(&observer2); subject.doSomething(); subject.detach(&observer2); subject.doSomething(); return 0; } ``` 在这个实现中,我们定义了一个 Observer 接口和一个 Subject 类。具体的观察者 ConcreteObserver1 和 ConcreteObserver2 实现了 Observer 接口,而具体的被观察者 ConcreteSubject 继承了 Subject 类。 ConcreteSubject 类中有一个 doSomething() 方法,它会触发 notify() 方法,通知所有注册过的观察者。被观察者可以通过 attach() 方法注册观察者,detach() 方法注销观察者。 在 main() 函数中,我们创建了 ConcreteSubject 和两个 ConcreteObserver 的实例,注册了这两个观察者,然后调用 doSomething() 方法触发通知。我们还演示了如何注销一个观察者,然后再次触发通知。 这个简单的实现可以帮助你理解观察者模式的基本原理和实现方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值