Статьи

Плагин DCI для Eclipse

Парадигма архитектуры данных, контекста и взаимодействия (DCI) вводит идею мышления в терминах ролей и контекстов. См. Некоторые из моих технических документов для более подробного введения в DCI, но для этой статьи блога рассмотрим следующий пример: человек может быть смоделирован в объектно-ориентированном программировании, создав супер огромный массив, который включает в себя все атрибуты людей, их поведение и т. д. Вы, вероятно, в конечном итоге получили бы что-то слишком сложное, чтобы его можно было по-настоящему поддерживать. Подумайте, когда человек станет клоуном для детской вечеринки; большая часть этого поведения не имеет ничего общего с тем, чтобы быть программистом, а это другая роль, которую может играть человек.

Итак, DCI смотрит на проблему иначе, чем ООП, и решает ее, позволяя классу данных быть хорошим классом данных и помещая поведения, специфичные для определенных ролей, в «роли», которые в моей библиотеке DCI Tools for Java являются классами.

Определенные роли взаимодействуют друг с другом в данном контексте, например, развлечение детей клоуна на вечеринке по случаю дня рождения. Роли, которые принадлежат взаимодействию, являются частью контекста, а в DCI контекст является классом, который помещает объекты данных в конкретные роли и заставляет их взаимодействовать. Контекст и его роли формируют инкапсуляцию поведения.

Я обновил свою библиотеку, так что появились две новые аннотации, а именно аннотации @Context и @Role. Аннотация @Context — это просто маркер, показывающий, что класс является контекстом. Аннотация @Role более важна. Он помещается в класс интерфейса роли и сообщает контексту, где найти реализацию роли, и дополнительно требует, чтобы программист специально указал, к какому контексту относится роль.

Код в конечном итоге выглядит следующим образом. Сначала модульный тест, который создает и вызывает контекст:

  @Test
public void testExecute() {

//create an adult (the clown) and some children,
//and let the party start...

Human adult = new Human();
List children = new ArrayList();
Human child = new Human();
child.setName("Johnny");
children.add(child);
child = new Human();
child.setName("Jane");
children.add(child);

ClownContext cc = new ClownContext(adult, children.toArray());
cc.startParty();

//check the party went well...
assertEquals(0, adult.getHappiness());
for (Human c : children) {
assertEquals(1, c.getHappiness());
}
}
}

В вышеприведенном коде нет ничего особенного. Он просто создает некоторые объекты данных и передает их в контекст, а затем запускает вечеринку (взаимодействие или вариант использования). Далее показан класс контекста:

/** the context in which a clown entertains some kids. */
@Context
public class ClownContext extends BehaviourInjector {

/** the object who will play the clown role */
private Object adult;

/** the objects who will play the kid role */
private List children;

/**
* Creates a new Context object. takes "objects" rather than specific types to allow it to be reusable.
*/
public ClownContext(Object adult, Object[] children) {
this.adult = adult;

this.children = new ArrayList();

for (Object child : children) {
this.children.add(child);
}
}

/** start the interaction */
public void startParty() {
Clown clown = assignRole(adult, Clown.class);

clown.applyMakeup();

IIterable kids = getIterable(children.iterator(), Kid.class);

clown.makeKidsLaugh(kids);
}

}

Контекст имеет несколько примечательных моментов. Прежде всего, это расширяет BehaviourInjector. Благодаря этому он получает доступ к методам assignRole (Object, Class) и getIterable (Iterator, Class). Обратите внимание на аннотацию @Context вверху — это важно не только для того, чтобы помочь программисту определить, что это контекст, но также и для плагина Eclipse, который я создал и который я представляю ниже.

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

Назначение роли — это то, где поведение «внедряется» в объект данных. Создаваемая итерация — это особая роль, которая может автоматически превращать человеческих детей в роль ребенка, посещающего вечеринку.

Далее взгляните на интерфейс роли. Этот класс определяет методы, которые объект данных должен играть, а также поведение, которое будет добавлено к объекту.

@Role(contextClass = ClownContext.class, 
implementationClass = ClownImpl.class)
public interface Clown {

/** put some makeup on (initialise) */
public void applyMakeup(); // role

/** makes kids laugh */
public void makeKidsLaugh(IIterable kids); // role

public void setHairColour(Color c); // data

}

Интерфейс роли имеет аннотацию @Role, которая сообщает инжектору поведения, во-первых, к какому контексту относится роль, а во-вторых, где можно найти фактическую реализацию (поведение). В роли клоуна, указанной выше, добавлено два поведения (нанесение макияжа и смешение детей). Применение макияжа дополнительно требует, чтобы клоун мог установить цвет своих волос, поэтому здесь также указывается метод, который должен иметь класс людей.

Наконец, класс реализации роли:

public class ClownImpl {

@Self
private Clown self;

/** @see Clown#applyMakeup() */
public void applyMakeup(){
self.setHairColour(Color.GREEN);
}

/** @see Clown#makeKidsLaugh(IIterable) */
public void makeKidsLaugh(IIterable kids) {
for (Kid kid : kids) {
kid.laugh();
System.out.println();
}
}
}

Реализация роли не требует реализации интерфейса роли! Это просто класс, на который инжектор поведения полагается, чтобы найти поведение, которое он не может найти в объекте данных. Аннотация @Self к полю клоуна под названием self является ссылкой на объект, играющий роль клоуна, и похожа на «this», только то, что «this» будет ссылкой на экземпляр реализации роли, а не на объект играет роль. Это позволяет получить доступ к методам данных объекта данных.

Теперь, не только помогая программисту мысленно связывать контексты с ролями, эти две аннотации позволяют выполнять статический анализ кода. Используя инфраструктуру Eclipse JDT, можно получить отдельные токены исходного кода, даже когда файлы классов не компилируются, для построения модели контекстов и ролей в проекте Java. Я создал небольшое представление DCI Outline для Eclipse, похожее на схему классов, за исключением того, что вместо классов показаны контексты и связанные с ними роли. Вот снимок экрана:

представление показывает все контексты, которые он находит в выбранном проекте Java. Для каждого контекста он показывает пакет, затем список его методов, а затем все роли, которые ему принадлежат.

Для каждого интерфейса роли указан пакет, а затем список методов, которые содержит интерфейс роли. В нижней части ветви роли находится класс реализации роли.

Идея этого плагина состоит в том, чтобы дать программисту представление о том, какие контексты доступны и какие роли они содержат. Он помещает контексты, роли и их методы в сознание программиста, позволяя им мыслить с точки зрения DCI, точно так же, как стандартный браузер классов позволяет программисту мыслить с точки зрения классов.

Двойной щелчок по интерфейсу роли, реализации роли или контексту откроет его в редакторе.

Плагин имеет ограниченные возможности проверки и может определять, например, если контекст, указанный в аннотации роли, не может быть найден в проекте, и выделяет это, чтобы программист мог увидеть, что есть проблема. В таких случаях вид выглядит следующим образом:

код из этого примера можно скачать
здесь .

Полное руководство по эксплуатации вместе с библиотекой DCI Tools for Java и сайтом обновлений Eclipse можно найти
здесь .

От http://blog.maxant.co.uk/pebble/2010/11/16/1289941080000.html