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

来源:互联网 发布:2017年进出口贸易数据 编辑:程序博客网 时间:2024/04/28 23:48

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

    请模拟下列情形:

  • 小孩在睡觉
  • 醒来后要求吃东西
       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;}@Overridepublic void run() {// TODO Auto-generated method stubtry {Thread.sleep(5000);//假设孩子睡5秒钟就醒来} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}this.WakeUp=true;}}class Dad implements Runnable{Child c;Dad(Child c){this.c=c;}@Overridepublic void run() {// TODO Auto-generated method stubwhile(!c.isWakeUp()){try {Thread.sleep(1000);//父亲每1秒就检查一次孩子有没有醒} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}feed(c);}private void feed(Child c) {// TODO Auto-generated method stubSystem.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;}@Overridepublic void run() {// TODO Auto-generated method stubtry {Thread.sleep(5000);//假设孩子睡5秒钟就醒来} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}d.feed(this);//孩子Child醒来主动调用Dad的feed()方法}}class Dad {public void feed(Child c) {// TODO Auto-generated method stubSystem.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;}@Overridepublic void run() {// TODO Auto-generated method stubtry {Thread.sleep(5000);//假设孩子睡5秒钟就醒来} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}d.ActionToWakeUp(new WakeUpEvent(System.currentTimeMillis(),this));//响应醒来事件}}class Dad {public void ActionToWakeUp(WakeUpEvent wakeUpEvent) {// TODO Auto-generated method stubif(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);}@Overridepublic void run() {// TODO Auto-generated method stubtry {Thread.sleep(5000);//假设孩子睡5秒钟就醒来} catch (InterruptedException e) {// TODO Auto-generated catch blocke.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 stubif(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 stubif(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);}@Overridepublic void run() {// TODO Auto-generated method stubtry {Thread.sleep(5000);//假设孩子睡5秒钟就醒来} catch (InterruptedException e) {// TODO Auto-generated catch blocke.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 stubif(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 stubif(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 stubif(wakeUpEvent.getTime()<12){//不同时间对孩子的响应也不同System.out.println("GrandMother feed child ...");}else{System.out.println("GrandMother hug child ...");}}}
    下面为配置文件wakeUpListeners.properties。

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

0 0
原创粉丝点击