Зачем заставлять себя реализовывать абстрактные методы в конкретных подклассах, если вместо этого мы можем использовать пустые конкретные методы? - PullRequest
0 голосов
/ 10 февраля 2011

После создания абстрактного суперкласса, когда вы доберетесь до первого конкретного подкласса, вам нужно реализовать все свои абстрактные методы, даже если некоторые из этих методов не будут использоваться в этом конкретном классе. ТАК! Почему абстрактный суперкласс просто не превращает эти абстрактные методы в «поддельные» методы, например:

public void doThis() { 
     if (1 < 0){ 
          int x = 34
     }
}

он ничего не делает, так как 1 никогда не меньше 0. И затем, когда вы попадаете в конкретный подкласс, вам не нужно реализовывать ВСЕ эти абстрактные методы, но для тех, которые вы ХОТИТЕ реализовать, вы можете просто переписать в метод вам нужно, чтобы это было:

public void doThis() {
      //does "this".
}

В обоих случаях возможен полиморфизм, верно? Так в чем же реальные преимущества абстрактных методов, которые мне не хватает?

Спасибо!

Ответы [ 5 ]

4 голосов
/ 10 февраля 2011

Если вы не реализуете все методы вашего абстрактного базового класса, значит, с вашим дизайном что-то не так.

2 голосов
/ 10 февраля 2011

Абстрактные методы защитят вас от ошибки частичной реализации подкласса. Если базовый метод конкретен и пуст, компилятор позволит вам переопределить некоторые виртуальные, но не другие.

В некоторых случаях это желаемый результат. Но обычно это не так.

2 голосов
/ 10 февраля 2011

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

a) абстрактный класс не может быть создан
и
b) вы должны "заполнить пробелы«для того, как делается абстрактная вещь - другими словами, вам нужно сделать абстрактную вещь конкретной.

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

Обратите внимание, что многие языки, такие как javascript, не имеют понятия «абстрактный», и людивсе еще пишу хорошее программное обеспечение с помощью JavaScript.

1 голос
/ 10 февраля 2011

Есть пара вещей, которые вы не рассматриваете.Существуют абстрактные классы и абстрактные методы.Абстрактные классы не могут быть созданы напрямую, они, так сказать, просто шаблоны.Абстрактные методы могут быть определены только в классе abstrac, и должно быть пустым (т. Е. Без тела), но мы все это знаем.Тем не менее, абстрактные классы могут предоставлять неабстрактные методы.Прекрасным примером является Log4j AppenderSkeleton (см. http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/AppenderSkeleton.html).

AppenderSkeleton - абстрактный класс. Он имеет конкретные методы, которые вы можете переопределить, у него есть абстрактный метод (append), который вы должны реализоватьесли вы наследуете (если ваш класс не является также абстрактным классом), и два метода, которые поступают из интерфейса Appender, которые также должны быть реализованы, или переданный как абстрактный для любого дочернего класса (close и requireLayout).

Теперь, если вы хотите написать своего собственного аппендера, скажем, для чирикания чего-то, вы должны начать с:

public class TweetAppender extends AppenderSkeleton {

    public boolean requiresLayout() {
        return false;
    }

    public void close() {
        // do nothing        
    }

    @Override
    protected void append(LoggingEvent event) {
        // take the message and tweet it!
    }    
}

Итак, всехитросплетения, связанные с ведением журнала (с использованием фильтров, уровней настройки, обработчиков ошибок), скрыты от вас. Вы просто должны вести реальное ведение журнала, а log4j сделает все остальное за вас. Конечно, ваш TweetAppender может переопределить другие методы, еслиВы хотите. Возможно, вы хотите сделать специальную обработку ошибок, в этом случае вам просто нужно переопределить setErrorHandler.

Теперь представьте, что вы также хотите внедрить приложение для Facebook и другихОдин, чтобы изменить свой статус в Skype.Предположим, что все они предоставляют API через веб-сервисы для публикации обновлений статуса, изменений и т. Д. Довольно скоро вы поймете, что есть пара вещей, которые могут быть похожими, например, вызов веб-сервисов и т. Д.Кроме того, вы заметили, что в Skype есть какой-то формат, а в твиттере - другой, а что нет.Итак, вы решили создать WebServiceAppender:

public abstract class WebServiceAppender extends AppenderSkeleton {
    public boolean requiresLayout() {
        return false;
    }

    public final void close() {
        // do extra clean up of resources
    }

    // make this final so no one can do strange stuff
    protected final void append(LoggingEvent event) {
        // do a lot of stuff, like, opening up a connection
        // send an xml, close the connection and stuff...
        // ...
        // ready to send the message!
        final String messageToSend = getFormattedMessage(event);
        // send the message and do lots of complicated stuff
        // ...
        // close and clean up
    }

    // let the implementations decide on the format
    protected abstract String getFormattedMessage(LoggingEvent event); 
}

Теперь ваш TweetAppender будет выглядеть как

public class TweetAppender extends WebServiceAppender {
    @Override
    protected String getFormattedMessage(LoggingEvent event) {
        // use tweeter's specific format
    }

    public boolean requiresLayout() {
        return super.requiresLayout();
    }
}

. Объявляя getFormattedMessage абстрактным, WebServiceAppender заставляетлюбая реализация фактически обеспечивает реализацию, которая принимает LoggingEvent и возвращает String.Обратите также внимание на то, что, объявив методы append и close как окончательные, WebServiceAppender запрещает любой имплементации переопределять эти методы.Метод requireLayout все еще открыт для переопределения.

Еще одна интересная особенность классов, унаследованных от абстрактных классов, - это использование super.Думайте об этом как о родительском классе 'this.В случае TweetAppender реализация метода requireLayout решает в основном отложить ответственность за принятие решения о том, требуется ли этому приложению макет или нет, просто используя родительский класс.

Итак, собрав все вместе:

public class YourParentClass {
    public void doThis() { 
       if (1 < 0){ 
           int x = 34
    } 
}

public class YourChildClass extends YourParentClass {
    @Override
    public void doThis() {
        // do I want to do this, or something else?
        if (iGuessIWillDoThis) {
            super.doThis();
        } else {
            // do something else
        }
    }
}

В любом случае, мои два цента.

0 голосов
/ 10 февраля 2011

Это зависит от того, зачем вам нужен абстрактный метод. Например, шаблон проектирования «Шаблонный метод» требует, чтобы абстрактный метод возвращал значение. Очевидно, что компилятор не может угадать, какое значение вы хотите вернуть.

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