Как спроектировать инфраструктуру расширяемого типа с зависимостями между собой - PullRequest
1 голос
/ 09 января 2010

Мое приложение - это редактор для подключения «модулей» (через порты модулей).Порты имеют типы портов.Каждый тип порта имеет свой связанный компаратор.Два типа совместимы, если их атрибуты удовлетворяют правилам, реализованным в компараторе.

Я хочу, чтобы пользователи расширяли приложение, внедряя новые типы портов и правила их подключения (через инфраструктуру точек расширения eclipse).

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

Я реализовал эти два интерфейса:

public interface IPortType {
    [many attributes]
}
public interface IComparator {
    public boolean isCompatible(IPortType source, IPortType target);

    // more interaction methods!
}

Мое текущее решение немного уродливо, так как универсальный метод isCompatible (источник IPortType, цель IPortType)является своего рода делегатом и должен быть переписан во всех подклассах.Простая перегрузка метода isCompatible () здесь не работает.

Но еще большим недостатком является нарушение принципа открытого-закрытого: необходимо расширять все конкретные классы Comparator, когда должен поддерживаться новый тип.Но как сохранить количество классов правил на низком уровне, когда существует больше взаимодействий между типами, такими как преобразование и т. Д.?Я хотел сохранить все правила для одного типа в одном классе.

Пример конкретного компаратора:

public class ATypeComparator implements IComparator {

    public boolean isCompatible(IPortType source, IPortType target) {
        if (!(source instanceof AType))
            return false;
        if (target instanceof BType)
            return isCompatible(source, (BType) target);
        if (target instanceof CType)
            return isCompatible(source, (CType) target);
    }

    public boolean isCompatible(AType source, BType target) {...}
    public boolean isCompatible(AType source, CType target) {...}
}

Как бы вы решили эту проблему?

Спасибо за любыепредложения!

Ответы [ 2 ]

1 голос
/ 09 января 2010

Я не считаю правильным, чтобы реализация IPortType решала, совместима ли она с другими реализациями IPortType. Это просто не часть его ответственности.

Простым решением было бы создание одного открытого статического метода, например, в классе PortTypeManager, который знает, совместимы ли две реализации IPortType. Таким образом, вы всегда можно добавить новый тип, и вам нужно всего лишь изменить логику в одном месте, чтобы приспособить этот новый тип.

Однако, в конце концов, этого также будет недостаточно, потому что число случаев, которые должен охватывать метод, растет как n ^ 2. Вам необходимо предоставить каждой реализации IPortType такой метод, как getVersion () или getSignature (), который возвращает фрагмент данных, который можно сравнить с аналогичным фрагментом данных, чтобы решить, совместимы ли две реализации.

0 голосов
/ 09 января 2010

Казалось бы, ваша реализация могла бы быть очищена, если бы вы позволили полиморфизму обрабатывать сложности.

Не проще ли иметь метод .compatibleTo() на IPortType? Если бы вы могли сделать это, каждая реализация могла бы знать, что она поддерживает конечные точки, которые она может поддерживать?

Что-то вроде:

IPortType port1 = ...
IPortType port2 = ...

if (port.compatibleTo(port2)) {
    // do whatever
}
...