首页 文章

OSGi UI应用程序中的最佳实践

提问于
浏览
5

我对OSGi世界有些新意 . 还有一些概念让我望而却步 .

我正在尝试使用Swing,Equinox和Declarative Services创建一个图形OSGi应用程序 . 目标是简化应用程序的插件和扩展的创建 .

我偶然发现了一个设计问题,因为我从头开始这样做,所以我希望尽可能使用所有最佳实践 .

我有一个包含API的包,只公开要实现为服务的接口 .

public class SomeClass {
}

public interface Manager<T> {
     void add(T obj);
     void update(T obj);
     void remove(T obj);
}

public interface SomeClassManager extends Manager<SomeClass> {
}

public interface Listener<T> {
    void added(T obj);
    void updated(T obj);
    void removed(T obj);
}

public interface SomeClassListener extends Listener<SomeClass> {
}

假设我有一个包( Core ),它提供的服务是某些类型对象的管理器(它基本上包含一个内部List并添加,删除和更新它) .

public class SomeClassCoreManager implements SomeClassManager {

      private ArrayList<SomeClass> list = new ArrayList<SomeClass>();
      private ArrayList<SomeListener> listeners = new ArrayList<SomeListener>();

      protected void bindListener(SomeListener listener) {
            listeners.add(listener); 
      }

      protected void undindListener(SomeListener listener) {
            listeners.remove(listener);
      }

      public void add(SomeClass obj) {
          // Adds the object to the list
          // Fires all the listeners with "added(obj)"
      }


      public void update(SomeClass obj) {
          // Updates the object in the list.
          // Fires all the listeners with "updated(obj)"
      }

      public void remove(SomeClass obj) {
          // Removes the object from the list.
          // Fires all the listeners with "removed(obj)"
      }

}

我还有第二个包( UI )来处理主UI . 对于管理自身的对象,它不应该"care",但是在添加,删除或更改对象以更新JTree时应该通知它 . 为此,我使用了一个Whiteboard模式:UI包实现了一个服务,Core bundle使用该服务来触发对象更改事件 .

public class MainWindow extends JFrame {

     private JTree tree = new JTree();
     private SomeClassManager manager;

     protected void activate() {
          // Adds the tree and sets its model and creates the rest of the UI.
     }

     protected void bindManager(SomeClassManager manager) {
          this.manager = manager;
     }

     protected unbindManager(SomeClassManager manager) {
          this.manager = null;
     }
}

public class SomeClassUIListener implements SomeClassListener {
     public void added(SomeClass obj) {
          // Should add the object to the JTree.
     }

     public void updated(SomeClass obj) {
          // Should update the existing object in the JTree.
     }

     public void removed(SomeClass obj) {
          // Should remove the existing object from the JTree.
     }

}

我的问题如下:

MainWindow是一个DS组件 . 我正在使用它的激活器来启动整个UI . 实例创建由OSGi处理 .

为了从管理器获取更新,我将SomeClassUIListener公开为声明式服务 . 它的实例也由OSGi处理 .

How should I access the instance of the JTree model from the SomeClassUIListener?

我提出了几个选项,但我不确定使用哪个:

Option 1: 为UI包(如Guice或Pico)使用某种内部DI系统,并将其放在具有静态方法的类中以获取它并在整个包中使用它 .

一些人似乎不赞成这种做法 .

Option 2: 通过OSGi在SomeClassUIListener中注入对MainWindow的引用(通过将其转换为服务)并从那里开始 . 这是可行的还是可取的?在我看来,这是更简单的解决方案 . 但是,另一方面,随着UI变得越来越复杂,这不会使组件配置文件变得混乱吗?

Option 3: 仅为侦听器创建单独的包,并使用OSGi更新MainWindow . 这在我看来有点极端,因为随着UI复杂性的增长,我将不得不创建大量的bundle .

Option 4: 使用MainWindow类实现监听器 . 但是,主UI包中的服务越多,MainWindow类就越大 . 我认为这不是一个好选择 .

我想不出更多选择 . 以上任何一种方式都可以吗?还是有其他选择吗?

先感谢您 .

Edit:

只是为了澄清Peter Kriens对这个问题有些怀疑 .

我的目标是将用户界面与Manager分离 . 通过管理器我的意思是一种存储库,我在其中存储某种类型的对象(例如,如果你在http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html考虑Oracle的JTree教程,那么管理器将包含Books的实例) .

管理员可以被任何其他捆绑使用,但根据我目前的计划,它会通知在其中注册的任何听众 . 侦听器可以是主UI包,但也可以是选择侦听更新的任何其他包 .

3 回答

  • 0

    我不确定我是否完全掌握了您的建议,感觉您正在创建一整套基础架构 . 在OSGi中,这通常不是必需的,所以为什么不从小而简单开始 .

    您的基本模型是经理和扩展 . 这是域模型,我会尝试在这里流动:

    @Component(immediate)
    public class ManagerImpl { // No API == immediate
       List<Extension>  extensions  = new CopyOnWriteArrayList<Extension>();
       JFrame frame = new JFrame();
    
       @Reference(cardinality=MULTIPLE) 
       void addExtension( Extension e ) {
           addComponent(frame, e.getName(), e.getComponent());
           extensions.add(e);
       }
    
       void removeExtension( Extension e) {
         if ( extensions.remove(e) ) {
            removeComponent(frame, e.getName());
       }
     }
    
     @Component 
     public class MyFirstExtension implements Extension {
        public String getName() { return "My First Extension";}
        public Component getComponent() { return new MyFirstExtensionComponent(this); }
     }
    

    这不是你想要的吗?要非常小心不要创建各种类型的侦听器,通常你会发现OSGi注册表中已有的事件 .

  • 1

    这里的一些选项是将树模型实例作为侦听器方法中的参数传递 .

    public void added(JTree tree, SomeClass obj)
    

    这种方式,侦听器管理器只负责侦听器逻辑,而不是树状态 .

    另一个不错的选择是创建一个单独的 TreeProviderService ,负责为应用程序保存和提供单例 JTree 实例 . 在这种情况下,您将直接从侦听器使用 TreeProviderService .

  • 0

    我建议简单地使用DS来创建和连接UI . 如果您使用Peter提到的注释,您将不会使用XML格式的组件描述符来混乱您的bundle .

    因此,您的侦听器是@Component,并且您需要将更新所需的UI元素注入其中 .

    顺便说一句 . 你打算做什么听起来有点像数据绑定给我所以你也应该调查这些提供的内容 . 见:Swing data binding frameworks

    顺便说一句 . 您可能还想寻找比swing更高级的框架 . 例如前段时间我为vaadin做了一个小教程:https://github.com/cschneider/Karaf-Tutorial/tree/master/vaadin它已经有了java bean的数据绑定 . 所以这使我很容易编写UI代码 . 完整的UI就是这个小类:https://github.com/cschneider/Karaf-Tutorial/blob/master/vaadin/tasklist-ui-vaadin/src/main/java/net/lr/tutorial/karaf/vaadin/ExampleApplication.java

    在旧版本中,我仍然需要一个桥接来在OSGi中运行vaadin,但版本7应该是OSGi准备就绪 .

相关问题