Filter/Compontent pattern instead of clumsy inheritance?
I have a:
class ServiceObject {
ServiceClass svcClass;
void execute(String operation, Map arguments, ...) {
svcClass.execute(this, operation, arguments, ...);
}
}
Then I have a subclass of that to add in synchronization:
class SynchronizedServiceObject extends ServiceObject {
void execute(String operation, Map arguments, ...) {
synchronized(lock) {
super.execute(operation, arguments, ...);
}
}
}
I also have a subclass to add a logging context
class LogContextServiceObject extends ServiceObject {
void execute(String operation, Map arguments, ...) {
MDC.set("context", myCtx);
super.execut开发者_如何学编程e(operation, arguments, ...);
MDC.remove("context");
}
}
However, if I want to use both features, I would need to write another subclass which has them both. You can imagine that with more added features (logging, request rewriting, etc.) I would have to write a lot of classes for every combination I need.
Instead, I'd like to ditch the subclasses and pass some sort of filter or component objects at the creation of ServiceObject
. What's a recommended pattern for this (In Java, or in general).
In terms of famous GoF book: Decorator.
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);
}
}
}
After all you can combine them as you like:
ServiceObject serviceObject =
new LoggingDecorator(
new SynchronizedDecorator(
new ServiceObjectImpl()
)
);
Easiest solution is to create a factory class and enumerator:
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 ();
}
}
}
Usage:
ServiceObject blah1 = ServiceObjectFactory.NewService(ServiceObjectType.SynchronizedServiceObject);
ServiceObject blah2 = ServiceObjectFactory.NewService(ServiceObjectType.LogContextServiceObject);
It sounds very much like the Chain of Responsibility pattern. This is often described as propagating a request until some handler can take responsibility, but it is also used to propagate a request until some handler "consumes" it. In your case, you want to unconditionally propagate to all handlers.
精彩评论