我对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> {
}
假设我有一个捆绑包(核心),它提供的服务是某些类型对象的管理器(它基本上包含一个内部列表并添加,删除和更新它)。
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。它不应该“关心”管理自身的对象,但是在添加,删除或更改对象以更新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处理。
我应该如何从SomeClassUIListener访问JTree模型的实例?
我提出了几个选项,但我不确定使用哪个选项:
选项1: 使用某种内部DI系统作为UI包(如Guice或Pico),并将其放在一个静态方法的类中,以获取它并在整个包中使用它。
这种方法似乎被一些人不赞成。
选项2: 通过OSGi在SomeClassUIListener中注入对MainWindow的引用(通过将其转换为服务)并从那里开始。这是可行的还是可取的?在我看来,这是更简单的解决方案。但是,另一方面,随着UI变得越来越复杂,这会不会使组件配置文件变得混乱?
选项3: 仅为侦听器创建单独的包,并使用OSGi更新MainWindow。这在我看来有点极端,因为随着UI复杂性的增加,我将不得不创建大量的包。
选项4: 使用MainWindow类实现Listener。但是,主UI包中的服务越多,MainWindow类就越大。我认为这不是一个好的选择。
我想不出更多选择。以上任何一种方式都可以吗?或者还有其他选择吗?
提前谢谢。
修改
只是澄清彼得克里恩斯对这个问题有些怀疑。
我的目标是将用户界面与Manager分离。通过 Manager 我的意思是一种存储库,我在其中存储某种类型的对象(例如,如果你在http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html考虑Oracle的JTree教程,那么管理器将包含Books的实例)
管理员可能被任何其他捆绑使用,但根据我目前的计划,它会通知在其中注册的任何听众。侦听器可以是主UI包,但也可以是选择侦听更新的任何其他包。
答案 0 :(得分:1)
我不确定我是否完全掌握了您的建议,感觉您正在创建一整套基础架构。在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 :(得分:0)
这里的一些选项是将树模型实例作为侦听器方法中的参数传递。
public void added(JTree tree, SomeClass obj)
这种方式,侦听器管理器只负责侦听器逻辑,而不是树状态。
另一个不错的选择是创建一个独立的TreeProviderService
,负责为应用程序保存和提供单例JTree
实例。在这种情况下,您将直接从侦听器中使用TreeProviderService
。
答案 2 :(得分: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代码。完整的用户界面只是这个小课程: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准备就绪。