2013-11-26 3 views
4

Я немного новичок в мире OSGi. И некоторые концепции все еще ускользают от меня.Лучшая практика в приложении OSGi UI

Я пытаюсь создать графическое приложение OSGi с использованием Swing, Equinox и Declarative Services. Цель состоит в том, чтобы облегчить создание плагинов и расширений для приложения.

Я столкнулся с проблемой дизайна, и, поскольку я делаю это с нуля, я хочу использовать все лучшие практики, которые я могу.

У меня есть пакет, содержащий 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,), который предоставляет услугу, которая является менеджером некоторых типов объектов (Это в основном содержит внутренний список и добавляет, удаляет и обновляет его).

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), который заботится о главном пользовательском интерфейсе. Он не должен «заботиться» о том, чтобы объект сам управлял, но должен быть уведомлен о добавлении, удалении или изменении объекта для обновления JTree. Для этого я использовал шаблон Whiteboard: пакет UI реализует службу, которая используется пакетом Core для запуска событий изменения объекта.

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. Я использую его активатор, чтобы инициировать весь пользовательский интерфейс. Создание экземпляра обрабатывается OSGi.

Чтобы получить обновления от менеджера, я подвергаю SomeClassUIListener как декларативную услугу. Его экземпляр также обрабатывается OSGi.

Как получить доступ к экземпляру модели JTree у SomeClassUIListener?

Я придумал несколько вариантов, но я не уверен, какой из них использовать:

Вариант 1: Используйте какой-то внутренней системы DI для расслоения UI (например Guice или Пико) и поставить он в классе со статическим методом, чтобы получить его и использовать его по всему набору.

Этот подход, по-видимому, не одобряется некоторыми.

Вариант 2: Вводите ссылку на MainWindow (путем превращения его в эксплуатацию) в SomeClassUIListener через OSGi и идти оттуда. Возможно ли это или целесообразно? Мне кажется, что это более простое решение. Но, с другой стороны, разве это не помешало бы пакету с файлами конфигурации компонентов, так как интерфейс стал все более сложным?

Вариант 3: Создайте отдельный комплект только для слушателей и используйте OSGi для обновления MainWindow. Это кажется мне немного экстремальным, так как мне придется создавать огромное количество пакетов, поскольку сложность пользовательского интерфейса возрастает.

Вариант 4: Используйте класс MainWindow для реализации прослушивателя. Но чем больше услуг в пакете основного UI, тем больше будет класс MainWindow. Я думаю, это не будет хорошим вариантом.

Я не могу придумать больше вариантов. Есть ли какие-либо из вышеперечисленных способов? Или есть другой вариант?

Заранее спасибо.

Edit:

Просто чтобы прояснить, как Питер Крайенс были некоторые сомнения по поводу этого вопроса.

Моя цель - отделить пользовательский интерфейс от Менеджера. К Менеджер Я имею в виду репозиторий, в котором я храню определенный тип объектов (например, если вы рассматриваете учебник JTree от Oracle по адресу http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html, менеджер будет содержать экземпляры книг).

Менеджер может использоваться любым другим пакетом, но, согласно моему текущему плану, он уведомит зарегистрированного в нем слушателя. Слушателем может быть основной пакет пользовательского интерфейса, но также может быть любым другим пакетом, который хочет слушать обновления.

+1

В OSGi в книге действий от Ричарда Холла есть программа GUI в качестве примера, основанного на этой модели. Вы также можете посмотреть http://felix.apache.org/site/apache-felix-application-demonstration.html –

+0

Я проверил приведенные вами примеры. В исходном коде книги есть что-то, что может ответить на мой вопрос! В главе 11, в примере paint-example-ds, windowlistener намекает на решение: я мог зарегистрировать слушателя при привязке SomeClassCoreManager к MainWindow. таким образом я могу впрыскивать любые компоненты, которые мне нужны в слушателе. Источники, о которых я упоминал, можно найти в [link] (https://code.google.com/p/osgi-in-action/) –

ответ

0

Некоторым вариантом здесь было бы передать экземпляр модели дерева в качестве аргумента в методах слушателей.

public void added(JTree tree, SomeClass obj) 

Этот менеджер слушателей будет отвечать только за логику слушателей, а не за состояние дерева.

Другим приятным вариантом было бы создать разделенный TreeProviderService, ответственный за проведение и обслуживание экземпляра Singleton JTree для приложения. В таком случае вы будете потреблять TreeProviderService непосредственно у слушателей.

+0

Спасибо за ваш вклад, Henryk. Что касается вашего первого варианта. Будет ли JTree услугой, предоставляемой пользовательским интерфейсом, и другой пакет будет использовать ее при активации изменения события? О вашем втором варианте: для того, чтобы держать JTree, нужен отдельный комплект. Или услуга будет предоставляться и потребляться в комплекте UI? –

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.

+0

Это не похоже на то, что я ищу. Но я могу ошибаться! Как я могу поместить это в примере, который я дал, где у меня есть источник данных (диспетчер) и дисплей (UI)? Во всяком случае, я обновил сообщение, чтобы дать дополнительную информацию. –

0

Я предлагаю просто использовать DS для создания пользовательского интерфейса и подключения. Если вы используете аннотации, упомянутые Петром, вы не будете загромождать свои пакеты с дескрипторами компонентов в форме XML.

Итак, ваш слушатель является @Component, и вы вводите элементы пользовательского интерфейса, которые ему нужно обновить.

КПП. то, что вы планируете делать, немного напоминает привязку ко мне, поэтому вы также должны изучить, что они предлагают. См.: Swing data binding frameworks

КПП. вы также можете искать более продвинутые фреймворки, чем качать. Например, некоторое время назад я сделал небольшой учебник для vaadin: https://github.com/cschneider/Karaf-Tutorial/tree/master/vaadin У него уже есть привязка к java beans.Поэтому мне очень легко было кодировать пользовательский интерфейс. Полный интерфейс - вот этот маленький класс: https://github.com/cschneider/Karaf-Tutorial/blob/master/vaadin/tasklist-ui-vaadin/src/main/java/net/lr/tutorial/karaf/vaadin/ExampleApplication.java

В старой версии мне все еще нужен мост для запуска vaadin в OSGi, но версия 7 должна быть полностью готова к OSGi.

+0

В вашем предложении использовать DS, у меня были бы связанные услуги в их собственном пакете, или я должен создать другие пакеты? Что касается привязки данных, это также кажется интересным. Но это означало бы, что я должен отказаться от всей архитектуры OSGi? Также возможно использование более продвинутых фреймворков, кроме Swing. Сохранение хорошо разделенных данных может дать мне возможность изменить структуру пользовательского интерфейса в будущем. –

+0

Я не уверен, насколько хорошо работает привязка данных к OSGi. Вероятно, это зависит от структуры привязки данных. В ваадине это работало хорошо. Btw. В настоящее время я изучаю использование CDI на OSGi. Преимущество в том, что оно знакомо людям JavaEE, и у него есть хорошее разделение проводки внутри и между пучками. Я не пытался подключить к нему пользовательский интерфейс swing, но это должно быть очень хорошо: https://github.com/cschneider/Karaf-Tutorial/tree/master/tasklist-cdi –

Смежные вопросы