Родительский метод переноса дочернего класса - PullRequest
3 голосов
/ 20 июня 2019

У меня есть классы Worker, выполняющие некоторую работу:

class WorkerOne implements IWorker {
    @Override
    public doWork(Resource resource){
     // do some work
    }
}

Я хочу, чтобы все doWork() методы были обернуты одной и той же операцией.

В одну сторонудля этого создайте абстрактный класс в следующем примере:

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
    }
}

и вызовите Worker как:

WorkerOne worker = new WorkerOne();
worker.doBetterWork();

По некоторым причинам я предпочитаю не использовать наследование.Есть ли лучшее решение для такой упаковки?

Ответы [ 2 ]

4 голосов
/ 20 июня 2019

С помощью метода default, который вы можете определить в интерфейсах, вы можете избежать наследования (extends) и придерживаться реализации (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();
    }
}

И используйте это, как вы делали ранее:

IWorker worker = new WorkerOne();
worker.doBetterWork(); 

Я хочу, чтобы все методы doWork () были заключены в одну и ту же операцию.

Лично мне не очень нравятся дизайны, в которых я раскрываю два метода в терминах API, в то время как клиенты этого класса должны вызывать только один из них. Это вводит в заблуждение.
Чтобы избежать этого, я бы, вероятно, использовал композицию и декоратор (не обычный декоратор, так как подпись отличается между двумя doWork() методами).

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...
    } 
 }

Теперь двусмысленность невозможна:

WorkWrapper worker = new WorkWrapper(new FooWork());
worker.doWork(); // just this method is exposed now in WorkWrapper 

Вы можете объединить его с фабрикой, чтобы упростить задачу и скрыть детали реализации со стороны клиента:

WorkWrapper worker = FooWork.createWrapperFor();
worker.doWork(); 
2 голосов
/ 20 июня 2019

Ситуация, которую вы описываете, кажется точным контекстом, в котором можно применить шаблон проектирования Template Method .Однако эти шаблоны действительно требуют наследования.

Есть альтернативы.Тем не менее, это настолько хорошо подходит для ваших требований, что я бы не стал называть их «лучшими» решениями.

Очевидной альтернативой наследования является композиция.В вашем случае это будет означать применение шаблона Strategy .

При применении этого шаблона ваш WorkWrapper станет context , а IWorker будет соответствоватьроль абстрактной стратегии , с ее реализациями в качестве конкретных стратегий .

В коде:

class WorkWrapperContext {
    private IWorker strategy;

    WorkWrapperContext(IWorker strategy) { 
        this.strategy = strategy;
    }

    public void doBetterWorkOperation() {
        // do some stuff
        strategy.doWork();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...