I have these Worker classes doing some job:
class WorkerOne implements IWorker {
@Override
public doWork(Resource resource){
// do some work
}
}
I want all doWork() methods to be wrapped by the same operation.
One way to achieve it is creating an abstract class as the following example:
abstract class WorkWrapper implements IWorker {
@Override
public doBetterWork(){
Resource resource = // ...
doWork(resource)
resource .close();
}
}
class WorkerOne extends WorkWrapper {
protected doWork(Resource resource){
// do some work
}
}
and invoke the Worker as:
WorkerOne worker = new WorkerOne();
worker.doBetterWork();
For some reasons I prefer not to use inheritance. Is there a better solution to do this wrapping?
With default method that you can defined in interfaces you could avoid inheritance (extends) and stick to implement (implements) :
class WorkerOne implements IWorker {
@Override
public void doWork(Resource resource){
// do some work
}
}
public interface IWorker {
void doWork(Resource resource);
default void doBetterWork(){
Resource resource = // ...
doWork(resource)
reource.close();
}
}
And use it like you previously did :
IWorker worker = new WorkerOne();
worker.doBetterWork();
I want all doWork() methods to be wrapped by the same operation.
Personally I don't like very much designs where I expose two methods in terms of API while only one of them should be invoked by clients of the class. That is misleading.
To avoid it, I would probably use composition and decorator (not the conventional decorator as the signature differs between the two doWork() methods).
public interface IWorker {
void doWork(Resource resource);
}
class WorkWrapper{
private IWorker decorated;
public WorkWrapper(IWorker decorated){
this.decorated = decorated;
}
@Override
public doWork(){
Resource resource = // ...
decorated.doWork(resource);
reource.close();
}
}
class FooWork implements IWorker {
@Override
public doWork(Resource resource){
// do something...
}
}
Now no ambiguities is possible :
WorkWrapper worker = new WorkWrapper(new FooWork());
worker.doWork(); // just this method is exposed now in WorkWrapper
You can combine it to the factory to make things simpler and hiding implementation details from client side:
WorkWrapper worker = FooWork.createWrapperFor();
worker.doWork();
The situation you are describing seems to be the exact context where one would apply the Template Method design pattern. However, that patterns does, indeed, call for inheritance.
There are alternatives. However, it's such a good fit for your requirements that I would hesitate to call them "better" solutions.
The obvious alternative to inheritance is composition. In your case this would mean applying the Strategy pattern.
In applying this pattern your WorkWrapper would become the context, and the IWorker would match the role of the abstract strategy, with its implementations serving as the concrete strategies.
In code:
class WorkWrapperContext {
private IWorker strategy;
WorkWrapperContext(IWorker strategy) {
this.strategy = strategy;
}
public void doBetterWorkOperation() {
// do some stuff
strategy.doWork();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With