Выкройка декоратор - как украсить сразу два вида

я работаю на Яве

Я создал красивую структуру декораторов для ребер графа. У меня есть базовое ребро с двумя вершинами, затем у меня есть взвешенный декоратор, который добавляет вес ребру, а затем у меня есть ориентированный декоратор, который добавляет ориентацию ребру. Декораторы реализуются с использованием интерфейсов и методов делегата (а не путем наследования).

Теперь я хотел бы добавить еще один декоратор - декоратор потока, соответствующий краю потока. Ребра потока имеют как направление, так и вес (пропускную способность), а также поток. Как мне реализовать что-то подобное в Java? мне нужно что-то вроде

public class FlowEdge implements IEdge, IWeightedEdge, IOrientedEdge, IFlowEdge
{
    private IEdge, IWeightedEdge, IOrientedEdge decorated;
    private int flow;

    //constructors, delegate methods...

но это явно невозможно.

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


person Jakub Zaverka    schedule 08.02.2012    source источник
comment
Почему это очевидно невозможно? Вы можете использовать только extend один класс, но implement любое количество интерфейсов.   -  person Ted Hopp    schedule 08.02.2012
comment
Я имел ввиду строку private IEdge, IWeightedEdge, IOrientedEdge оформленную; чтобы сохранить все типы, мне нужно будет реализовать методы делегата.   -  person Jakub Zaverka    schedule 08.02.2012


Ответы (4)


Декораторы реализуются с использованием интерфейсов и методов делегата (а не путем наследования).

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

person Yuriy Zubarev    schedule 08.02.2012
comment
Как мне тогда украсить один класс двумя декораторами? Я не могу наследовать от двух классов в Java. - person Jakub Zaverka; 08.02.2012
comment
Это не совсем так, как работают декораторы в Java. Вы не столько наследуете, сколько... украшаете во время выполнения. Например: новый BufferedReader(новый FileReader(readme.txt)). - person Yuriy Zubarev; 08.02.2012

Ваш дизайн кажется ошибочным. Декораторы обычно «обертывают» класс, который они хотят украсить, который передается в их конструктор. Ваш код должен сделать что-то вроде этого возможным:

Graph myGraph = new BaseGraph();
Graph decoratedGraph = new FlowedGraph(new WeightedGraph(new OrientedGraph(myGraph)));
person Bohemian♦    schedule 08.02.2012
comment
Спасибо... да, это декоратор, как меня учили. Но FlowedGraph должен иметь и направление, и вес, и я не могу гарантировать в этом случае, что получателем будет и то, и другое. Я могу сделать его только взвешенным или ориентированным. - person Jakub Zaverka; 08.02.2012

Я отказался от всей этой идеи декоратора и реализовал края так же, как обычное наследование.

Edge --> WeightedEdge --> OrientedEdge --> FlowEdge

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

person Jakub Zaverka    schedule 08.02.2012

Кажется ошибкой объявлять тип оформления, который реализует декоратор. Также декоратору кажется неправильным точно знать, что он украшает. Вы можете реализовать «составной декоратор», который полагается на другие классы декораторов, чтобы добавить определенное поведение в дополнение к новому поведению, которое оно обеспечивает. Возможно что-то вроде этого:

public class FlowEdge implements IEdge // or IFlowEdge
{
    private IEdge decorated;
    private int flow;

    public FlowEdge(IEdge decorated) {
        this.decorated = new WeightedEdge(new OrientedEdge(decorated));
        . . .
    }
}
person Ted Hopp    schedule 08.02.2012
comment
Интересная идея, но тогда у меня должны быть произвольные значения веса и направления, так как их нельзя передать в конструкторе (кроме проверки типа и последующего приведения к соответствующему типу). - person Jakub Zaverka; 08.02.2012
comment
@JakubZaverka - Почему в конструкторе нельзя передать соответствующие свойства? Из того, что вы описываете, свойства FlowEdge включают в себя все свойства WeightedEdge и OrientedEdge. Затем их можно передать соответствующим конструкторам внутри конструктора FlowEdge. (Возможно, я что-то неправильно понимаю; я не понимаю, почему вам нужно выполнять здесь какие-либо проверки и приведения типов.) - person Ted Hopp; 08.02.2012
comment
FlowEdge(WeightedEdge wedge, OrientedEdge oedge) Я некоторое время шел по этой дороге, но она не казалась чистой, можно было пройти два разных экземпляра. Я должен был бы проверить if(wedge != oedge), а затем выдать какое-то исключение. Это уже во время выполнения, я хотел бы проверить это во время компиляции. - person Jakub Zaverka; 09.02.2012