Кодирую себя в угол - PullRequest
       12

Кодирую себя в угол

10 голосов
/ 14 января 2010

У нас есть набор классов, которые наследуются от общего набора интерфейсов, таких что

IFoo-> BasicFoo, ReverseFoo, ForwardFoo
IBar -> UpBar, DownBar, SidewaysBar
IYelp -> Yip, Yap, Yup

где конструктор для Foo выглядит как Foo(IBar, IYelp) Эти элементы используются во всем проекте.

Существует другой класс, у которого есть метод с сигнатурой public double CalcSomething(IFoo, IAnotherClass), который применяется в какой-то момент к каждому Foo. Сверху мы получили запрос на то, чтобы одна конкретная композиция объектов, скажем, BasicFoo(UpBar,Yip), использовала другой алгоритм, отличный от алгоритма, найденного в CalcSomething.

Моим первым инстинктом было сказать, что давайте изменим интерфейс IFoo, чтобы мы могли переместить логику на уровень класса Foo, изменить конструктор на Foo(IBar, IYelp, IStrategy), а затем объекты Foo инкапсулировать эту логику. К сожалению, нам также сказали, что дизайн архитектуры предусматривает отсутствие зависимостей между IFoo, ее реализациями и IAnotherClass. Они непреклонны в этом.

Хорошо, конечно, тогда я подумал, что могу использовать шаблон посетителя, но ... как? Весь смысл создания композиции заключался в том, что ни один другой класс не мог видеть детали реализации. Отражение, чтобы заглянуть внутрь объектов, полностью нарушая инкапсуляцию? О, черт возьми, нет.

Так что я пришел сюда, потому что я в растерянности. Есть ли у кого-нибудь предложения, как мы могли бы относиться к особому случаю одной из композиций без изменения композиции или нарушения инкапсуляции? Должно быть простое решение, на которое я смотрю.

Edit:

Удалено оскорбительное начало. Изменено «специально обработано» в более описательное значение.

Ответы [ 3 ]

3 голосов
/ 14 января 2010

В духе KISS я бы добавил метод isSpecial () в IFoo и использовал его, чтобы решить, какой алгоритм использовать в CalcSomething ().

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

3 голосов
/ 14 января 2010

A CalculationFactory, который выбирает подходящий алгоритм на основе типа IFoo, который вы предоставите, решит проблему (за счет условного):

interface ICalcSomethingStrategy {
    public double CalcSomething(IFoo, IAnotherClass);
}

CalcSomethingStrategyFactory {
    ICalcSomethingStrategy CreateCalcSomethingStrategy(IFoo foo) {
        // I'm not sure whether this is the idiomatic java way to check types D:
        if (foo.Bar instanceof UpBar && foo instanceof Yip) {
            return new UnusualCalcSomethingStrategy();
        } else {
            return new StandardCalcSomethingStrategy();
        }
    }
}
1 голос
/ 14 января 2010

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

Создание интерфейса маркера IQualifyForSpecialTreatment, который расширяет IFoo. Расширьте BasicFoo до SpecialBasicFoo и предложите ему реализовать IQualifyForSpecialTreatment.


    interface IQualifyForSpecialTreatment extends IFoo {
    }
    class SpecialBasicFoo extends BasicFoo implements IQualifyForSpecialTreatment {
        ...
    }

Затем вы можете добавить еще один вариант calcSomething:


    calcSomething (IQualifyForSpecialTreatment foo, IAnotherClass whatever) {
        ... perform "special" variant of calculation
    }
    calcSomething (IFoo foo, IAnotherClass whatever) {
        ... perform "normal" variant of calculation
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...