设计模式之Observer:小孩在睡觉,醒来后要求吃东西

    这两天在学设计模式,那么从下面这个例子来入手吧!

    请模拟下列情形:

  • 小孩在睡觉
  • 醒来后要求吃东西
       1.设计方式一
           一个Child类,一个Dad类,Dad时刻监听Child,看其是否醒过来,若醒来则喂奶。    
package pack1;

class Child implements Runnable{
	private boolean WakeUp=false;

	public boolean isWakeUp() {
		return WakeUp;
	}

	public void setWakeUp(boolean wakeUp) {
		WakeUp = wakeUp;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(5000);//假设孩子睡5秒钟就醒来
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.WakeUp=true;
	}	
}

class Dad implements Runnable{
	Child c;
	
	Dad(Child c){
		this.c=c;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(!c.isWakeUp()){
			try {
				Thread.sleep(1000);//父亲每1秒就检查一次孩子有没有醒
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		feed(c);	
	}

	private void feed(Child c) {
		// TODO Auto-generated method stub
		System.out.println("feed child ...");	
	}
	
}
public class Design1 {
	public static void main(String[] args) {
	
		Child c=new Child();
		Dad d=new Dad(c);
		Thread threadChild=new Thread(c);
		Thread threadDad=new Thread(d);
		threadChild.start();
		threadDad.start();
	}
}
    上述设计方式虽然实现了基本的功能,但是由于Dad类一直主动监测Child是否醒来,浪费资源。一种简单的改进方式为,让Child醒来后主动调用Dad的Feed()方法,具体实现如下设计方式二。
     2.设计方式二
      Child类醒来主动调用Dad的Feed()方法。
package pack2;

class Child implements Runnable{
	private Dad d;

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

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(5000);//假设孩子睡5秒钟就醒来
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		d.feed(this);//孩子Child醒来主动调用Dad的feed()方法
	}	
}

class Dad {
	public void feed(Child c) {
		// TODO Auto-generated method stub
		System.out.println("feed child ...");
	}	
}

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

}
    设计方式二较好的完成了情形的模拟,节省了资源。我们考虑更复杂的一下情况,若孩子不同时间醒来,爸爸的响应要不同怎么办?
   3.设计方式三
    为了实现对不同时间孩子醒来的不同响应,我们把孩子醒来封装成一个事件类WakeUpEvent。
package pack3;

class WakeUpEvent{
	private long time;
	private Object obj;
	
	public WakeUpEvent(long time, Object obj) {
		super();
		this.time = time;
		this.obj = obj;
	}
	public long getTime() {
		return time;
	}
	public void setTime(long time) {
		this.time = time;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
}

class Child implements Runnable{
	private Dad d;

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

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(5000);//假设孩子睡5秒钟就醒来
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		d.ActionToWakeUp(new WakeUpEvent(System.currentTimeMillis(),this));//响应醒来事件
	}	
}

class Dad {
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {
		// TODO Auto-generated method stub
		if(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同
			System.out.println("feed child ...");
		}else{
			System.out.println("hug child ...");
		}
	}	
}

public class Design3 {
	public static void main(String[] args) {
		Dad d=new Dad();
		Child c=new Child(d);
		Thread threadChild=new Thread(c);
		threadChild.start();
	}
}
    设计方式三已经较全面的模拟了孩子醒来响应的基本情形,但此种方法的扩展性不好,例如,孩子醒来爷爷奶奶也有响应又怎么办?总不能来一个响应者就修改一次源代码吧?
    4.设计方式三
      使用接口,让所有响应者都实现WakeUpListener接口,并在Child类中使用响应者列表,使其可以动态添加响应者。
package pack4;

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

class WakeUpEvent{
	private long time;
	private Object obj;
	
	public WakeUpEvent(long time, Object obj) {
		super();
		this.time = time;
		this.obj = obj;
	}
	public long getTime() {
		return time;
	}
	public void setTime(long time) {
		this.time = time;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
}

interface WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent);
}

class Child implements Runnable{
	private List<WakeUpListener> wakeUpListeners=new ArrayList<WakeUpListener>(); 

	public void addWakeUpListener(WakeUpListener l){
		wakeUpListeners.add(l);
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(5000);//假设孩子睡5秒钟就醒来
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//所有的响应者都对孩子醒来做出响应
		for(int i=0;i<wakeUpListeners.size();i++){
			WakeUpListener l=wakeUpListeners.get(i);
			l.ActionToWakeUp(new WakeUpEvent(System.currentTimeMillis(),this));
		}
	}	
}

class Dad implements WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {
		// TODO Auto-generated method stub
		if(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同
			System.out.println("Dad feed child ...");
		}else{
			System.out.println("Dad hug child ...");
		}
	}	
}

class GrandFather implements WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {
		// TODO Auto-generated method stub
		if(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同
			System.out.println("GrandFather feed child ...");
		}else{
			System.out.println("GrandFather hug child ...");
		}
	}	
}

public class Design4 {
	public static void main(String[] args) {
		Dad d=new Dad();
		GrandFather gf=new GrandFather();
		Child c=new Child();
		c.addWakeUpListener(d);//添加父亲响应者
		c.addWakeUpListener(gf);//添加爷爷响应者
		Thread threadChild=new Thread(c);
		threadChild.start();
	}
}
     此方法实现了动态添加响应者,它虽然不用修改Child类程序,但是还是要修改main()方法程序来添加响应者。
    5.设计方式五
     为了实现不修改任何程序而添加响应者,我们使用反射机制,通过读配置文件的方法来动态添加响应者。
package pack5;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

class WakeUpEvent{
	private long time;
	private Object obj;
	
	public WakeUpEvent(long time, Object obj) {
		super();
		this.time = time;
		this.obj = obj;
	}
	public long getTime() {
		return time;
	}
	public void setTime(long time) {
		this.time = time;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
}

interface WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent);
}

class Child implements Runnable{
	private List<WakeUpListener> wakeUpListeners=new ArrayList<WakeUpListener>(); 

	public void addWakeUpListener(WakeUpListener l){
		wakeUpListeners.add(l);
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			Thread.sleep(5000);//假设孩子睡5秒钟就醒来
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//所有的响应者都对孩子醒来做出响应
		for(int i=0;i<wakeUpListeners.size();i++){
			WakeUpListener l=wakeUpListeners.get(i);
			l.ActionToWakeUp(new WakeUpEvent(System.currentTimeMillis(),this));
		}
	}	
}

public class Design5 {
	public static void main(String[] args) throws Exception {
		Child c=new Child();
		
		//创建配置文件
		File configFile=new File("wakeUpListeners.properties");
		Properties prop=new Properties();
		FileInputStream fis=new FileInputStream(configFile);
		prop.load(fis);
		
		for(int i=0;i<prop.size();i++){
			//获取响应者类名称
			String wakeUpListenerName=(String)prop.get("wakeUpListener"+(i+1));
			//根据类名称获取class文件
			Class clazz=Class.forName(wakeUpListenerName);
			WakeUpListener wakeUpListener=(WakeUpListener)clazz.newInstance();
			c.addWakeUpListener(wakeUpListener);		
		}
		fis.close();
		
		Thread threadChild=new Thread(c);
		threadChild.start();
	}
}

    以下分别为响应者类Dad、GrandFather、GrandMother,它们实现了统一的接口WakeUpListener,为了使用java的反射机制,都应为public类型的类。
package pack5;

public class Dad implements WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {
		// TODO Auto-generated method stub
		if(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同
			System.out.println("Dad feed child ...");
		}else{
			System.out.println("Dad hug child ...");
		}
	}	
}
package pack5;

public class GrandFather implements WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {
		// TODO Auto-generated method stub
		if(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同
			System.out.println("GrandFather feed child ...");
		}else{
			System.out.println("GrandFather hug child ...");
		}
	}	
}
package pack5;

public class GrandMother implements WakeUpListener{
	public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {
		// TODO Auto-generated method stub
		if(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同
			System.out.println("GrandMother feed child ...");
		}else{
			System.out.println("GrandMother hug child ...");
		}
	}	
}
    下面为配置文件wakeUpListeners.properties。

    若后期还需添加其他的响应者,则只需实现WakeUpListener接口,并在配置文件中加入响应类的名称条目即可,实现了无需修改源代码而动态添加响应者。
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下是一个使用观察者(Observer设计模式的示例代码(C++): ```cpp #include <iostream> #include <vector> // 观察者接口 class Observer { public: virtual void update(const std::string& message) = 0; }; // 具体观察者A class ConcreteObserverA : public Observer { public: void update(const std::string& message) override { std::cout << "具体观察者A收到消息:" << message << std::endl; } }; // 具体观察者B class ConcreteObserverB : public Observer { public: void update(const std::string& message) override { std::cout << "具体观察者B收到消息:" << message << std::endl; } }; // 被观察者(主题)类 class Subject { private: std::vector<Observer*> observers; std::string message; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { for (auto it = observers.begin(); it != observers.end(); ++it) { if (*it == observer) { observers.erase(it); break; } } } void notify() { for (auto observer : observers) { observer->update(message); } } void setMessage(const std::string& newMessage) { message = newMessage; notify(); } }; // 客户端代码 int main() { // 创建具体观察者对象 Observer* observerA = new ConcreteObserverA(); Observer* observerB = new ConcreteObserverB(); // 创建被观察者对象 Subject subject; // 注册观察者 subject.attach(observerA); subject.attach(observerB); // 设置消息并通知观察者 subject.setMessage("Hello World!"); // 取消注册观察者B subject.detach(observerB); // 设置新消息并通知观察者 subject.setMessage("Goodbye!"); delete observerA; delete observerB; return 0; } ``` 在上述示例代码中,我们定义了一个观察者接口 `Observer`,并要求具体的观察者类继承并实现该接口。具体的观察者类 `ConcreteObserverA` 和 `ConcreteObserverB` 分别定义了不同的更新行为。 被观察者(主题)类 `Subject` 包含一个观察者列表,并提供了注册、注销和通知观察者的方法。通过调用 `notify()` 方法,被观察者会遍历观察者列表,并调用每个观察者的 `update()` 方法来传递消息。 在客户端代码中,我们创建了具体的观察者对象,并将它们注册到被观察者中。然后,通过设置消息并调用被观察者的 `setMessage()` 方法来通知观察者。在示例中,我们设置了两条消息,并在第二条消息后注销了一个观察者。 运行代码将输出每个观察者收到的消息。 这个示例展示了观察者设计模式的基本结构和使用方式,并在 C++ 中实现了它。通过使用观察者模式,可以实现对象之间的松耦合,当一个对象的状态发生变化时,它的所有观察者都会得到通知并进行相应的处理。记得在程序结束时删除动态分配的内存。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值