Это декоратор или шаблон стратегии, или ни один из двух? - PullRequest
8 голосов
/ 24 января 2012

У меня есть следующий интерфейс.

PowerSwitch.java

public interface PowerSwitch {
    public boolean powerOn();
    public boolean powerOff();
    public boolean isPowerOn();
}

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

Я хотел бы добавить функциональность к интерфейсу PowerSwitch во время выполнения (что делают декораторы), создав класс, который содержит композицию экземпляра PowerSwitch и добавляет новые методы, такие как два toggleOnOff () методы ниже. Таким образом, мне нужно реализовать два метода переключения только один раз, и это будет применяться ко всем реализациям PowerSwitch.

Считается ли это хорошей / плохой практикой? Если плохо, какие-либо другие рекомендации?

Это на самом деле не соответствует шаблону декоратора, поскольку добавляет дополнительные методы. Это шаблон стратегии или шаблон композиции? Или у него есть другое имя шаблона? Есть ли такая вещь как «интерфейсный декоратор»?

PowerSwitchDecorator.java

public class PowerSwitchDecorator {
    private PowerSwitch ps;

    public PowerSwitchDecorator(PowerSwitch ps) {
        this.ps = ps;
    }

    public void toggleOnOff(int millis) throws InterruptedException{
        powerOn();
        Thread.sleep(millis);
        powerOff();
    }

    public void toggleOnOff(){
    powerOn();
    powerOff();
    }

    public boolean powerOn() {
        return ps.powerOn();
    }

    public boolean powerOff() {
        return ps.powerOff();
    }

    public boolean isPowerOn() {
        return ps.isPowerOn();
    }
}

Ответы [ 7 ]

7 голосов
/ 24 января 2012

Как таковой, любой код, который хочет использовать методы toggleOnOff(int) или toggleOnOff(), будет нуждаться в экземпляре PowerSwitchDecorator, а не PowerSwitch. Этот вид поражает цель декоратора, который должен быть прозрачным для клиента.

Если вы хотите, чтобы все реализации имели эти методы, вы должны включить их в интерфейс PowerSwitch.

Затем, как предлагает @Ani, вы можете изменить вышеприведенный PowerSwitchDecorator, чтобы расширить PowerSwitch, чтобы вы могли сделать это:

PowerSwitch switch = new PowerSwitchDecorator(new ConcretePowerSwitch());
switch.toggleOnOff();

Теперь у вас есть переменная типа PowerSwitch с возможностями PowerSwitchDecorator.

РЕДАКТИРОВАТЬ: Обратите внимание, что вы должны использовать только установленный шаблон, если он соответствует вашим потребностям. Вы можете использовать подход, который вы показали, если он работает для вас. Не нужно подгонять его по определенному шаблону.

Какой тип объекта вы хотите передать? Вам нужны такие методы в вашем API:

void connect(PowerSwitch powerSwitch, Appliance appliance);

Или такие методы:

void connect(PowerSwitchDecorator powerSwitch, Appliance appliance);

(извините, это не очень хорошие примеры)

Если вы хотите первое, то каждый должен будет вручную «украсить» свои PowerSwitch, чтобы получить пару удобных методов. Сейчас это может быть удобно для вас, но я думаю, что это будет неудобно для пользователей вашего кода, и они, вероятно, не будут беспокоиться об этом. Если вы хотите последнее, вы должны использовать тип PowerSwitchDecorator в сигнатурах вашего метода, что означает, что вы всегда имеете дело с PowerSwitchDecorator s, а не с необработанными PowerSwitch es.

3 голосов
/ 24 января 2012

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

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

Расширение класса является хорошей практикой, когда вам нужно улучшить или переопределить поведение при компиляции.

0 голосов
/ 03 июня 2016

Ваш класс PowerSwitchDecorator не является декоратором.Ваша реализация близка к Strategy_pattern , хотя команды похожи на Command_pattern

В шаблоне Decorator, Decorator фактически реализует интерфейс (то есть Component) иваш класс не делает то же самое.

Посмотрите на диаграмму классов

enter image description here

На приведенной выше диаграмме Component - этоинтерфейс.Decorator реализует интерфейс Component и содержит интерфейс с Composition.Посмотрите на переменную-член - component.

См. Эти вопросы для лучшего понимания:

Шаблон декоратора для ввода-вывода

Пример шаблона стратегии в реальном мире

0 голосов
/ 24 января 2012

Я бы сказал, что это не один из шаблонов.

Шаблон декоратора

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

public class ScrollBarsWindow : Window
{
     private Window windowToDecorate;
     public ScrollBarsWindow(Window windowToDecorate)
     {
         this.windowToDecorate = windowToDecorate;
     }

     public void Draw()
     {
         windowToDecorate.Draw();
         DrawScrollBars();
     }

     public void DrawScrollBars()
     { Draw the scroll bars }
 }

Схема стратегии

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

public interface IMakeCoffeeStrategy
{
    public Coffee MakeCoffee();
}

public class CappuccinoStrategy : IMakeCoffeeStrategy
{
    public Coffee MakeCoffee { make your cappuccion }
}

public class LatteStrategy : IMakeCoffeeStrategy
{
    public Coffee MakeCoffee { make your latte }
}

public class Context
{
    private IMakeCoffeeStrategy strategy;
    public Context(IMakeCoffeeStrategy strategy)
    {
        this.strategy = strategy;
    }

    public Coffee MakeSomeCoffee()
    {
        return strategy.MakeCoffee();
    }
}

и используйте его как

public class MyCoffeeMachine
{
    public Coffee MakeCoffee(CoffeeType coffeeType)
    {
        if(coffeeType == CoffeeType.Latte)
            return new Context(new LatteStrategy()).MakeSomeCoffee();
        else if(coffeeType == CoffeeType.Cappuccino)
            return new Context(new CappuccinoStrategy()).MakeSomeCoffee();

       ...
    }
}

Прочитайте следующие ссылки для получения дополнительной информации:

0 голосов
/ 24 января 2012

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

С вашим кодом реальной разницы пока нет.Это похоже на стратегию, поскольку PowerSwitchDecorator просто делегирует работу (то есть алгоритм) PowerSwitch.Если это ваше намерение и есть альтернативные переключатели PowerSwitch по-разному, шаблон стратегии - ваш выбор.

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

0 голосов
/ 24 января 2012

Это ни один из паттернов.

Декоратор намерен обернуть объект и расширить уже существующую функциональность, делая интерфейс прозрачным для клиента.BufferedInputstream является примером.Обратите внимание, что Decorator должен реализовывать тот же интерфейс, что и тип, который вы переносите.

//Let Type be the interface that both the Decorator and DecoratedClass implements
Type yourInstance = new Decorator(new DecoratedClass());

Обратите внимание на отличие от Proxy-pattern, в котором основное намерение состоит в том, чтобы контролировать доступ к объекту, а не обязательно путем обертывания другого объекта.В этом случае вы также позволите прокси реализовать тот же интерфейс.

0 голосов
/ 24 января 2012

Было бы действительно декоратором, если бы декоратор также реализовал интерфейс PowerSwitch. Я бы охарактеризовал это как агрегацию объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...