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

class Service
{
function DoStuff()
{
variable1 = 1
variable2 = 2
variable3 = 3
}
}

class ServiceDecorator
{
function DoStuff()
{
parent DoStuff()
// Raise an event with variables listed in the service class function.
}
}
0
pro100tom 5 Янв 2022 в 02:22
1
«У меня есть класс обслуживания, который творит чудеса». - Означает ли это, что у него есть единственный метод void, который что-то делает, и никакой внешний код (клиенты или производные) не может сказать, что происходит, или иметь какое-либо взаимодействие, кроме вызова «запустил и забыл»? Если это так, то вы должны изменить это на что-то более структурированное.
 – 
Filip Milovanović
5 Янв 2022 в 04:32
1
Например, вы можете передать эти переменные соответствующему виртуальному методу, который производный класс может переопределить, но по умолчанию он ничего не делает.
 – 
Filip Milovanović
5 Янв 2022 в 04:35
Отличный момент! У меня есть функция, которая должна создавать сущность; это так, но он также сохраняет его в базе данных.
 – 
pro100tom
5 Янв 2022 в 13:36

2 ответа

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

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

Так что да, если кто-то сталкивается с подобной проблемой, сначала проверьте, не делает ли ваша функция больше, чем должна!

1
pro100tom 5 Янв 2022 в 14:02

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

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

Возьмем, к примеру, интерфейс для обработки веб-запросов:

public interface WebService {
    void handle(HttpRequest request, HttpResponse response)
}

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

public class TelemetryWebService {
    private WebService wrapped

    public TelemetryWebService(WebService handler) {
        wrapped = handler
    }

    public handle(HttpRequest request, HttpResponse response) {
        context = new TelemetryContext(request)
        context.sendBeginMessage(request)

        wrapped.handle(request, response)

        context.sendEndMessage(request)
    }
}

Вот что такое Декоратор.

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

  • Атрибуты private принадлежат только тому классу, в котором они определены
  • Доступ к атрибутам protected может получить класс, в котором они определены, а также любой класс, который расширяет этот класс.
  • Доступ к атрибутам public может получить любой код со ссылкой на ваш объект

Поэтому, если вы хотите раскрыть внутреннее состояние вашего базового класса, вы должны принять сознательное решение сделать это состояние доступным. Чтобы защитить себя от того, что вещи за пределами вашего класса изменят его работу, лучше всего сделать это состояние доступным только для чтения. Это обычно делается как метод "геттера". В некоторых языках есть синтаксический сахар, называемый свойствами. В любом случае, будьте осторожны с тем, что вы позволяете изменять состояние в вашем классе.

5
Berin Loritsch 5 Янв 2022 в 05:41
Я вижу вашу точку зрения. Но теперь я в замешательстве. Я видел примеры создания цепочки экземпляров, такие как «новый DecoratorA (новый DecoratorB (новый класс ()))». В вашем примере мы не сможем их связать. Я что-то упускаю? Допустим, мы хотим иметь один декоратор для регистрации событий, а другой — для создания событий. С вашим решением это невозможно.
 – 
pro100tom
5 Янв 2022 в 13:42
Как бы вы не связали их так, как я это сделал? Конструктор декоратора принимает любой объект, реализующий интерфейс WebService. Еще один декоратор, реализующий тот же интерфейс. Я не понимаю, как мой пример исключает эти примеры.
 – 
Berin Loritsch
5 Янв 2022 в 16:56