Поделиться кодом (который использует абстрактную операцию) между двумя классами - PullRequest
3 голосов
/ 06 марта 2011

Я разрабатываю серверное приложение на Java. Серверу нужны два типа серверных классов. Эти классы имеют несколько общих методов, код этих методов точно такой же. Поэтому я создаю абстрактный суперкласс, содержащий весь общий код, и оба класса наследуют его. Но есть некоторая часть кода, которая должна быть уточнена подклассами. Я имею в виду, что суперкласс "полагается" на методы подклассов.

Вот чистый пример того, что я имею в виду:

public abstract class AbstractServer
{
    public void loadConfig(String configPath)
    {
        //Load the configuration file.

        //This code is exactly the same for subclasses.
    }

    public void startRMI(int port)
    {
        //Create an empty RMI registry.
        //This part also need to be identical.

        //Here' where the superclass "rely" on subclasses.
        fillRegistry(); //Call the method overwritten by subclasses.
    }

    /**
    Bind remote objects in the RMI registry
    */
    protected abstract void fillRegistry(); //This method will be overriten by subclasses.
}

Я чувствую, что так плохо делать, но я не могу найти другого более чистого способа сделать это.

Итак, я хочу дать несколько советов о том, как мне сделать это лучше.

Спасибо, и извините за мой плохой английский.

Ответы [ 6 ]

0 голосов
/ 02 июля 2019

Ваш подход хорош, но ему нужно простое улучшение, чтобы сделать его идеальным - используйте метод startRMI() final:

public final void startRMI(int port) {
    fillRegistry();
}

Таким образом, вы предотвратите его переопределение (возможно, потому чтоне зная, что все в startRMI() должно быть повторно использовано, и что только fillRegistry() должно быть настроено).

Ваше решение обычно соответствует шаблону проектирования шаблона :

Метод шаблона является методом в суперклассе, обычно абстрактном суперклассе, и определяет каркас операции с точки зрения количества шагов высокого уровня.Эти шаги сами реализуются дополнительными вспомогательными методами в том же классе, что и метод шаблона.

Вспомогательные методы могут быть либо абстрактными методами, для которых подклассы требуются для предоставления конкретных реализаций, либо методами перехвата, которые имеют пустые тела в суперклассе. Подклассы могут (но не обязаны) настраивать операцию путем переопределения метода ловушки s.Целью метода шаблона является определение общей структуры операции , в то же время позволяя подклассам уточнить или переопределить определенные этапы .(Википедия)

Учитывая вышеизложенное, метод startRMI() представляет собой шаблонный метод, который определяет каркас операции с помощью ряда высокоуровневых шагов (в вашем случае это только один шаг, ноэто не имеет значения).Метод fillRegistry() в вашем примере является шагом высокого уровня - он определен как абстрактный метод в суперклассе и имеет конкретную реализацию в суперклассах.

С другой стороны, если вы переопределите методstartRMI() в подклассе, это больше не будет нормально.Вот почему вы должны сделать это final, чтобы избежать путаницы - таким образом, кто-то, кто создает подкласс, будет знать, что он должен реализовать fillRegistry() (так как он абстрактный), но не должен изменять реализацию startRMI (так как он финальный).

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

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

Ваш подход просто отлично.Придерживайся этого, приятель.

Я чувствую твою «философскую потребность» понять это.Базовый класс «полагаться» на подкласс хорошо, если базовый класс абстрактный.Он знает, что некоторые вещи должны быть зарегистрированы в этот момент, но он не имеет ни малейшего понятия о том, что именно должно быть зарегистрировано.Таким образом, процесс высокого уровня кодируется в базовом классе с помощью «дырок», которые могут быть подключены производным классом.Процесс высокого уровня и положение самой «дыры» ценно, и это оправдывает реализацию базового класса.Производные классы просто следуют основному принципу ОО «кодирование по разнице» и закрывают «дыры».

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

Во-первых, нет ничего плохого в том, чтобы требовать реализации подклассов в абстрактных (базовых) классах. Это просто то, что не следует злоупотреблять, ИМО. Однако, если бы мне пришлось этого избежать, я бы сделал ServerClass , а не абстрактным, и определил каждый его метод. Вместо этого я бы создал классы RegistryFactory и передал бы их классу ServerClass:

class ServerClass {
   public void startRMI(int port, RegistryFactory rf) {
      // ...
      rf.fillRegistry(this);
   }
}


interface RegistryFactory {
   /**
    * Implement this method
    */
   public void fillRegistry(ServerClass server);
}

public class RMIRegistryFactory implements RegistryFactory {
   public void fillRegistry(ServerClass server) { /* ... */ }
}

Или что-то в этом роде.

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

Я бы также удостоверился, что ваш суперкласс на самом деле абстрактный.В этом фрагменте это не так.В целом, выглядит неплохо.

Также рассмотрите возможность объявления любых переменных экземпляра в вашем суперклассе, которые также потребуются классам, которые его расширяют.

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

Суперкласс наследуется подклассом.Вы можете написать методы в суперклассе, которые вы хотите сделать общими, и оставить их нетронутыми.Для другой части кода, которую вы хотите перезаписать подклассами, определите другой набор методов в суперклассе.написать методы в подклассах также.когда вы вызываете метод из подкласса, вы можете поместить для вызова метода суперкласса

, короче говоря, вы должны писать методы в подклассе для перезаписи методов суперкласса.

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

Мне кажется, что вы правы после ваших правок (при условии, что вы исключили часть, генерирующую исключение для удобства чтения):)

Все три метода должны вызывать исключения в реальном мире.

...