题目不是很清楚,我仔细说来。
1. 要求任意一个Object都可以成为Observer。但是你不可以使用统一的接口。【这种我们称为非侵入式,有统一接口的称为侵入式】
2. 要求考虑线程问题。比如我们的Observer是一个SWT的对象,或者是一个Swing的对象,但是时间的fire者在其他的Work Thread。要求处理线程切换。
3. 
大致的样子应该满足这样的代码规范。class MyObserver {
    void onEventMessage(...) {}
}
你可能需要注册他。
那么我们大致可能会写成这个样子。
register(new MyObserver());
然后在某一个线程,我们可能回调事件给这个Observer。当然了。有很多个Observer,可是它们并非派生自同一个接口哦。
fire(o, /*some event*/);
大概是这个样子。
如果我们希望MyObserver 对象还关注其他的事件,只要在里面加个方法就可以了。当然了,你可以考虑命名耦合,这没有关系。
这次不考算法了,上次居然看到了C语言的答案。
大多数的Java程序员第一个想到的肯定是公共的接口,但是这个很简单,而实际中的系统可能有许多事件,你很难划分事件的接口从属。
以QQ为例,用户上线的回调事件接口方法,和用户消息到来的回调事件接口方法,是应该放到一个接口声明中嘛?
你想想? 使劲想,想不通的时候,你们就知道接口编程的经典也是一种痛苦了。会让你在设计阶段就耗费很多时间和精力。
好了,200分,给两个人。不明白的地方尽快问我。其他的别扯。

解决方案 »

  1.   

    题目也不是那么无聊,这都得从我做金山词霸开始,我了解了COM的回调,后来我自己设计了一个软件,模仿了这种结构,在后来的岁月中,我发现曾经看到的Tomcat源码充斥着这种设计,但是在设计和需求变换的时候,我觉得这种方法固然经典,但是问题也很多。后来我用C#做了一个引擎,去完全解决这个问题。
    系统被化简了,但是因为我使用了名字,使得系统的重构变成一个问题了。
      

  2.   

    首先声明,我不是高手,万一答案幼稚,各位大侠别笑话哈~我有个想法,可不可以写个类用于包装这个 Observer ,其中用一个 String 记录这个 Observer 应被事件触发的方法名,然后把这个 Observer 登记下来,当时间发生时,通过反射机制去调用事件方法。使用接口的典型 Observer 模式我用过,这样的题真是有创意……
      

  3.   

    或者这个被事件触发的方法名可以保存在登记 Observer 的类里,这样就可以除去包装类了。
      

  4.   

    问题很有意思,不过我还不是很明白.
    如果这个Observer类不知道会有什么样的事件会让自己处理,那自己是没有办法实现对应的方法的啊.因为我现在不做java了,我做.net,会定义一些event或者delegate.但是这个和定义接口其实是一样的.
    这个同样需要知道外界会有什么事件需要让自己来处理.不知道我说的你是否明白.其实如果你的需求只是需要设计一个组否flexible的Observer,让她能够很容易的去应变更多的需求,响应更多的事件.
    我觉得可以这么做.
    在Observer类里面设计一个方法,这个方法作为所有事件的转发中枢.这个方法只负责转发事件,而事件处理设计一个接口,在这个Observer类之外会有很多的实现这个接口的类,他们负责真正的处理事件.这个转发中枢函数对于实现类的调用可以使用反射,这样在Fire事件的时候,只要传进去对应事件的名字就可以.
    Register的时候,其实就是创建对应的事件处理实现类.
      

  5.   

    好像我上面说的和使用同一的Observer接口是一样意思,汗.../
      

  6.   

    我明白你说的,萧邦,我那个系统也是Delegate反射出来的,。所以这次想看看Java没有Delegate可以怎么玩比较好。你看,:还是四个星星的厉害,不愧是饼子堂里面的。
      

  7.   

    线程的问题由来:
    比如你做.Net,界面元素需要得到回调事件的时候,某个线程会Call这个Callback方法,但是方法中可能涉及到很多UI的元素。
    在.Net里面,我们会调用Control.Invoke吧? 实际就是Win32的SendMessage的封装,
    尽管我对Swing的了解不多,但是知道它的线程似乎也有类似的问题。所以我们得考虑啊?PS:实际上我做系统的时候,最讨厌这种不关逻辑表达的现场切换了。试想,如果我们有N个对象都是UI的元素,关注这个其他线程Send过来的消息,我们切换一次线程,还是多次呢?
      

  8.   

    Observer 包装类:public class ObserverPack {

    private Object obj = null;

    private Method onEventMethod = null;

    public ObserverPack(Object obj, String onEventMethod)
    throws SecurityException, NoSuchMethodException{
    this.obj = obj;
    this.onEventMethod = obj.getClass().getMethod(onEventMethod);
    }

    public void onEvent()
    throws IllegalArgumentException,
    IllegalAccessException, InvocationTargetException{
    onEventMethod.invoke(obj);

    }

    }
    事件及 Observer 管理类:public class Manager {

    public static final String AEVENT = "AEVENT";

    private Map<String, List<ObserverPack>> observerMap =
    new HashMap<String, List<ObserverPack>>();

    public void addObserver(Object object, String method, String eventName)
    throws SecurityException, NoSuchMethodException{
    if(observerMap.containsKey(eventName))
    observerMap.get(eventName).add(new ObserverPack(object, method));
    else{
    List<ObserverPack> observers = new ArrayList<ObserverPack>();
    observers.add(new ObserverPack(object, method));
    observerMap.put(eventName, observers);
    }
    }

    public void onEvent(String eventName)
    throws Exception{

    if(!observerMap.containsKey(eventName))
    throw new NoSuchEventException();

    for(ObserverPack op : observerMap.get(eventName))
    op.onEvent();

    }

    }
    原始 Observer 类:public class PrimalObserver {

    public void onEvent(){

    System.out.println("On Event!");

    }

    }
    不存在事件异常:@SuppressWarnings("serial")
    public class NoSuchEventException extends Exception {

    }
    测试类:public class ObserverTest { /**
     * @param args
     */
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    Manager manager = new Manager();

    PrimalObserver po = new PrimalObserver();

    try {
    manager.addObserver(po, "onEvent", Manager.AEVENT);
    } catch (SecurityException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (NoSuchMethodException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    try {
    manager.onEvent(Manager.AEVENT);
    } catch (IllegalArgumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (InvocationTargetException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    }}
    按我上面的思路实现的,不知道靠谱不靠谱,各位大侠不要拍我……
      

  9.   

    上面这一行应该改一下
    if(!observerMap.containsKey(eventName))
                throw new NoSuchEventException();
    我的原意是所有可能出现的事件都以 String 的形式作为常量保存在 Manager 中,然后当调用事件方法时,如果常量里不存在这个事件,就应该抛出这个异常,刚刚没细想,写成这样了……
      

  10.   

    你说的是不是设计模式里的那个Obsever啊???
    我觉得我们学的设计模式中讲到的Obsever绝对能满足你的要求了吧甘草...我强烈要求你加我MSN,你都不加我....
      

  11.   

    设计模式说用个List就可以啦....
    老师讲的挺好的嘛.....
    应该都知道吧...去年做了个类似LOG4J的一个LOG的library的时候我自己也有加如这个模式....
    甘草说的太玄乎了点吧...
    其实很简单吧...我们有几个设备是被观察的,另外几个设备是用来监测上述设备的变化的(相当于显示器),一旦被观察的设备发生变化我们就能动态地去告诉那些显示器嘛.....最多再多一个人动态加入和删除功能啊.....
    呵呵,貌似书上都有说的哦
    ^_^
    所以呢,强烈推荐headfirst(不知道谁翻译的中文名字好淫荡...深入浅出....)
      

  12.   

    MSN就是我的注册邮箱,163的。我只研究那些不实际的问题,加了也没用。
      

  13.   


    第一个问题 
    先说明这个思路很好 可以避免耦合 
    解决办法:看来只能用反射的办法了 
    先注册
    后循环取出 然后反射其方法 如果有fire的方法就调用之目前反射的性能已经足够好 性能不是问题
      

  14.   

    to xlong, good反射和线程关系不大,但是这个是一个系统,系统说粗俗了,就是把各种东西放进去,还不能乱。
      

  15.   

    反射和线程关系不大 是对的
    我的意思是:关于线程问题我想 不应该在调用方法上 
    应该在Obsever 的fire方法中处理
    而这个方法 是与你的业务逻辑相关的 
    不应与这个观察者模式耦合在一起
      

  16.   

    两个东西放在一起就是耦合嘛?或许你可以用两个系统完成这个事情。但是我把它们放在一起后,你感觉不到Thread的switch了。
    这才是一个框架。
      

  17.   

    大致看了下 不知道甘草说的和传统的Observer有什么区别
    线程? 反射?事件触发,回调 关注事态发展
      

  18.   

    啥是 Observer ?
      

  19.   

    比较高深的问题,有关线程切换,前两天用SWT的时候就碰到类似的问题,学习中