Шаблон фильтра / компонента вместо неуклюжего наследования? - PullRequest
1 голос
/ 21 марта 2011

У меня есть:

class ServiceObject {

    ServiceClass svcClass;

    void execute(String operation, Map arguments, ...) {
        svcClass.execute(this, operation, arguments, ...);
    }

}

Тогда у меня есть подкласс, который нужно добавить в синхронизации:

class SynchronizedServiceObject extends ServiceObject {

    void execute(String operation, Map arguments, ...) {
        synchronized(lock) {
            super.execute(operation, arguments, ...);
        }
    }

}

У меня также есть подкласс для добавления контекста ведения журнала

class LogContextServiceObject extends ServiceObject {

    void execute(String operation, Map arguments, ...) {
        MDC.set("context", myCtx);
        super.execute(operation, arguments, ...);
        MDC.remove("context");
    }

}

Однако, если я хочу использовать обе функции, мне нужно написать еще один подкласс, который имеет их обе. Вы можете себе представить, что с дополнительными функциями (ведение журнала, переписывание запросов и т. Д.) Мне пришлось бы написать множество классов для каждой нужной комбинации.

Вместо этого я хотел бы отказаться от подклассов и передать какой-либо объект фильтра или компонента при создании ServiceObject. Какой шаблон рекомендуется для этого (на Java или вообще).

Ответы [ 3 ]

4 голосов
/ 21 марта 2011

С точки зрения знаменитой книги GoF: Декоратор.

public class LoggingDecorator implements ServiceObject {

    private final ServiceObject decoratee;

    public LoggingDecorator(ServiceObject decoratee) {
        this.decoratee = decoratee;
    }


    @Override
    public void execute(String operation, Map<?, ?> arguments) {
        MDC.set("context", myCtx);
        try {
            decoratee.execute(operation, arguments);
        } finally {
            MDC.remove("context");
        }
    }
}

public class SynchronizedDecorator implements ServiceObject {

    private final ServiceObject decoratee;

    private final Object lock = new Object();

    public SynchronizedDecorator(ServiceObject decoratee) {
        this.decoratee = decoratee;
    }

    @Override
    public void execute(String operation, Map<?, ?> arguments) {
        synchronized (lock) {
            decoratee.execute(operation, arguments);
        }
    }
}

Ведь вы можете комбинировать их как хотите:

ServiceObject serviceObject =
                    new LoggingDecorator(
                            new SynchronizedDecorator(
                                    new ServiceObjectImpl()
                            )
                    );
0 голосов
/ 21 марта 2011

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

0 голосов
/ 21 марта 2011

Самое простое решение - создать фабричный класс и перечислитель:

enum ServiceObjectType { SynchronizedServiceObject ,LogContextServiceObject ,ServiceObject }
static class ServiceObjectFactory {
    ServiceObject NewService(ServiceObjectType  type) {
        switch(type) {
           case ServiceObjectType.SynchronizedServiceObject: return new SynchronizedServiceObject();
           case ServiceObjectType.LogContextServiceObject : return new LogContextServiceObject ();
           case ServiceObjectType.ServiceObject : return new ServiceObject (); 
        }
    }
}

Использование:

ServiceObject blah1 = ServiceObjectFactory.NewService(ServiceObjectType.SynchronizedServiceObject);
ServiceObject blah2 = ServiceObjectFactory.NewService(ServiceObjectType.LogContextServiceObject);
...