Мелкозернистый узор декоратора

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

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

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

Однако для поддержания полиморфизма это означало бы добавление тех методов к интерфейсу, которые реализуют декорированные объекты и объекты декоратора. Это нежелательно; они не должны быть общедоступными, и это фактически означает, что украшенный класс знает, как он будет украшен.

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


person Neil Barnwell    schedule 18.01.2010    source источник


Ответы (2)


Похоже, ваш API нарушает разделение команд и запросов, поэтому лучшим вариантом будет переработка API.

Однако, если я ошибаюсь или переделка невозможна, возможно, вы могли бы разделить метод декорированного класса на два метода без изменения интерфейса.

public interface IMyInterface
{
    Foo GetFoo(Bar bar);
}

public class MyClass : IMyInterface
{
    public Foo GetFoo(Bar bar)
    {
        this.DoSomethingWithSideEffects(bar);
        return this.DoSomethingToGetFoo(bar);
    }

    public Foo DoSomethingToGetFoo(Bar bar)
    {
        // ...
    }

    public void DoSomethingWithSideEffects(Bar bar)
    {
        // ...
    }
}

public class MyDecorator : IMyInterface
{
    private readonly MyClass mc;

    public MyDecorator(MyClass mc)
    {
        // put Null Guard here...
        this.mc = mc;
    }

    public Foo GetFoo(Bar bar)
    {
        return this.mc.DoSomethingToGetFoo(bar);
    }
}

Обратите внимание, что MyDecorator украшает MyClass вместо IMyInterface.

person Mark Seemann    schedule 18.01.2010
comment
Я не знаком с CQS, кроме названия - как я его нарушаю? - person Neil Barnwell; 19.01.2010
comment
Я не говорю, что вы нарушаете CQS, но нежелательные побочные эффекты часто являются признаком, указывающим в этом направлении. В CQS методы либо не имеют побочных эффектов, либо имеют только побочные эффекты. Однако в последнем случае побочный эффект никогда не бывает нежелательным. - person Mark Seemann; 19.01.2010

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

person Greg    schedule 18.01.2010
comment
Согласились, что данный сценарий очень похож на шаблон шаблона. - person Vincent Ramdhanie; 18.01.2010