class EventSet{
private Event[] events=new Event[100];
private int index=0;
private int next=0;
public void add(Event e){
if (index >= events.length)
return;
events[index++]=e;
}
public Event getNext(){
boolean looped=false;
int start=next;
do {
next=(next+1)%events.length;
if (start==next) looped=true;
if ((next==(start+1)%events.length) && looped)
return null;
}while (events[next]==null);
return events[next];
}
public void removeCurrent(){
events[next]=null;
}
}
public class Controller {
private EventSet es= new EventSet();
public void addEvent(Event c){es.add(c);};
public void run(){
Event e;
while ((e=es.getNext())!=null){
if (e.ready()){
e.action();
System.out.println(e.description());
es.removeCurrent();
}
}
}
}
EventSet可容纳100个事件,index在这里用于跟踪下一个可用的空间,而next帮助我们寻找列表中的下一个事件,了解自己是否已经循环到头。在对getNext()的调用中,这一点至关重要的,因为一旦运行,Event对象就会从列表中删去(使用removeCurrent())。所以getNext()会在向前移动时遇到“空洞”。
注意removeCurrent()并不只是指示一些标志,指出对象不再使用。相反,他将句柄设置为null。这一点非常的重要,因为假如垃圾收集器发现一个句柄仍然在使用,就不会清除对象。若认为自己的句柄可能像现在这样被挂起,那么做好将其设置为null,使垃圾收集器能够正常地清除他们。
Controller是进行实际工作的地方。它用一个EventSet容纳自己的Event对象,而且addEvent()允许我们向这个列表加入新事件。但重要的方法是run()。该方法会在EventSet中遍历,搜索一个准备运行的Event对象——ready()。对于它发现ready()的每一个对象,都会调用action()方法,打印出description(),然后将事件从列表中删除。
注意迄今为止我们仍然不能准确知道一个“事件”要做什么。这正是整个设计的关键;它怎样“将发生变化的东西同没有发生变化的东西区分开?”或者用我的话来讲,“改变的意图”造成了各类Event对象的不同行动,我们通过创建不同的Event子类,从而表达出不同的行动。
这正是内部类大显身手的地方,它允许我们做两件事情:
- 在单独一个类里表达一个控制框架应用的全部实施细节,从而完整地封装与那个实施有关地所有东西。内部类用于表达多种不同类型的action(),它用于解决实际的问题。除此之外,后续的例子使用了private内部类,所以实施细节完全隐藏起来,可以安全的修改。
- 内部类使我们具体的实施变得更加巧妙,因为能方便地访问外部类地任何成员。若不具备这种能力,代码看起来可能没那么使人舒服,最后不得不寻找其他方法
下面是Event类地代码:
abstract public class Event {
private long evtTime;
public Event(long eventTime){
evtTime=eventTime;
}
public boolean ready(){
return System.currentTimeMillis() >= evtTime;
}
abstract public void action();
abstract public String description();
}