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();