您的位置:首页 > 其它

观察者模式

2018-03-28 22:01 169 查看

观察者模式

 
分析与设计
我们要写这样的一个程序,孩子醒了要吃东西,老爸要喂东西给孩子吃。
实务上在没有分析清楚需求的时候我们是无法确定要做一个怎样的程序的,是一个图形化的?或者是命令行的?...所以在做所有的设计之前需要先做分析。分析需求就是要得出是什么来。当问题确定之后我们就可以进行规划如何实现这些分析出来的需求,设计讲求怎么做
现在我们不需要任何图像化的界面,我们用代码命令直接模仿这个情景。

Ention0
我们可以让老爸这个类(Dad)起一个线性用一个死循环去监听孩子(Child)的睡眠情况(睡眠情况可以用一个boolean变量来表示)。这个设计的缺点很明显,太占用CPU了!
 
Edtion1
我们不在用Dad这个类去不断的监听Child类的具体情况而是让孩子再醒来的时候告诉Dad一声也就是睡眠完成后直接调用父类喂食的方法。这样减少了CPU资源的消耗。但是还是不够灵活,因为Child类中会维护一个Dad的对象。如果现在孩子醒了爷爷,奶奶甚至是叔叔都要做出反应,这就需要在Child中维护很多的对象使得代码变得臃肿不堪。
 
Edtion2
既然Dad、GrandFather等类都要针对孩子的起床这个时间做出反应那么我们干脆把这个相同的过程抽象出来成为一个接口ActionListener(由于他们都在做监听这个动作并且做出反应)。而在Child类中只维护一个List集合用来存放ActionListener。在调用监听者的方法时直接遍历集合逐个调用。



但是这个方法还是不够灵活。如果我们现在的起床要分为不同的情况比如说上午气场与下午起床或者是在家里起床与在户外起床我们所表现的就会有所不同。进一步的推广到不仅仅是起床甚至是任何的事件我们都要做出不同的反应。
Edtion3
我们要写一个事件类的抽象类并且有各种属性的成员变量与一个对应参数的的构造器。当我们想有一个新的动作的时候就先去继承这个类然后调用父类的构造器产生具体的实例对象。当我们调用监听器类中的方法时要将事件对象传入,然后监听器接收到这个对象会根据不同的事件与其对应的属性进行执行不同的操作。



最后的优化
好设计不是去修改,而是添加。我们在添加监听器对象的时候会去在代码中添加语句如下所示:public class Test {
public static void main(String[] args) {
Child c = new Child();
c.addListener(new Dad());
c.addListener(new GrandFather());
c.makeAEvent(new WeakUpEvent(2018,"home",c));
}
}现在我们想要在添加监听器的时候不去修改代码而是去操作配置文件,所以我们将原来的代码改为如下所示:public class Test {
public static void main(String[] args) {
try {
Child c = new Child();
Properties props = new Properties();
props.load(Test.class.getClassLoader().getResourceAsStream("edtion03/observer.properties"));
String[] values = ((String) props.get("observers")).split(",");
for(String value : values) {
c.addListener((ActionListener)Class.forName(value).newInstance());
}

c.makeAEvent(new WeakUpEvent(2018,"home",c));
} catch (Exception e) {
e.printStackTrace();
}
}
}以下是properties中的内容(为了管理方便我们放到了包路径下)

observers=edtion03.Dad,edtion03.GrandFather
这样基本实现了灵活,但是读取properties文件的操作在工程中是常用的操作我们需要对读取properties文件的那部分代码封装到一个工具类中。这样既实现了代码的封装有降低了耦合度,当我们的读取文件代码改变时我们只需要修改一个类中的代码就ok了。最后出于内存占用与读取效率的考虑我们将propties读取文件的过程放到了静态代码块中实现了缓存(将访问频繁的代码放到内存而非硬盘中)。本次试验中所有的代码如下(都在一个类文件中):

package edtion04;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

//事件源
class Child{
//一个放有多个监听器的集合
private List<ActionListener> listeners = new ArrayList<ActionListener>();

//添加监听器
public void addListener(ActionListener listener) {
this.listeners.add(listener);
}

//执行每一个监听器所对应的方法
public void makeAEvent() {
Event event = new WeakUpEvent(2018,"home",this);
for(ActionListener listener : listeners) {
listener.ActiontoEvent(event);
}
}

public void run(Event event) {
try {
Thread.sleep(3000);
this.makeAEvent();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

//监听者
class Dad implements ActionListener{

@Override
public void ActiontoEvent(Event event) {
if(event instanceof WeakUpEvent) {
System.out.println("drink...");
}else if(event instanceof HungryEvent){
System.out.println("feed...");
}
}

}

class GrandFather implements ActionListener{

@Override
public void ActiontoEvent(Event event) {
if(event instanceof WeakUpEvent) {
System.out.println("watching TV...");
}else if(event instanceof HungryEvent){
System.out.println("KFC");
}
}

}
//监听器总类
interface ActionListener{
void ActiontoEvent(Event event);
}

//事件
class WeakUpEvent extends Event{
public WeakUpEvent(long time, String location, Object source) {
super(time, location, source);
}
}

class HungryEvent extends Event{
public HungryEvent(long time, String location, Object source) {
super(time, location, source);
}

}
abstract class Event{
private long time;
private String location;
private Object source;

public Event(long time, String location, Object source) {
super();
this.time = time;
this.location = location;
this.source = source;
}

public Object getSource() {
return source;
}
public void setSource(Object source) {
this.source = source;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getLocation() {
return location;
}
public void setLocatio
c297
n(String location) {
this.location = location;
}

}

class MyUtils{
private static Properties props = new Properties();
static {
try {
props.load(Test.class.getClassLoader().getResourceAsStream("edtion04/observer.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}

public static Object getValue(String key) {
return props.get(key);
}

}
public class Test {
public static void main(String[] args) {
try {
Child c = new Child();

String[] values = ((String) MyUtils.getValue("observers")).split(",");
for(String value : values) {
c.addListener((ActionListener)Class.forName(value).newInstance());
}

c.makeAEvent();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Awt事件响应模拟
Awt的事件响应与上面的思想类似,例如当我们点击按钮的时候会触发一些事件进而引起众多监听器的响应。以下附上awt的按钮事件响应响应:package edtionfinal;

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

public class SwingActionTest {
public static void main(String[] args) {
JButton button = new JButton();
button.addListener(new ActionListener1());
button.addListener(new ActionListener2());
button.pressed();
}
}

class JButton{
List<ActionListener> ActionListenerlist = new ArrayList<ActionListener>();
public void pressed() {
Event event = new MyEvent(System.currentTimeMillis(), this);
for(ActionListener listener : ActionListenerlist) {
listener.performed(event);
}
}

public void addListener(ActionListener actionListener) {
this.ActionListenerlist.add(actionListener);
}
}

interface ActionListener{
void performed(Event event);
}

class ActionListener1 implements ActionListener{

@Override
public void performed(Event event) {
System.out.println("action 1......");
}

}

class ActionListener2 implements ActionListener{

@Override
public void performed(Event event) {
System.out.println("action 2......");
}

}

abstract class Event {
private long when;
private Object source;
public Event(long when, Object source) {
super();
this.when = when;
this.source = source;
}

}

class MyEvent extends Event{
public MyEvent(long when, Object source) {
super(when, source);
}
}由此看来写一个不错的程序需要考虑到很多。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息