2011-02-10 3 views
0

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

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

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

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

Оба способа позволили бы полиморфизма, верно? Итак, каковы реальные преимущества абстрактных методов, которые мне не хватает?

Спасибо!

+0

Btw, вы говорите о C++ или java? Насколько мне известно, в Java интерфейсы почти всегда лучше, чем абстрактные базовые классы. – Falmarri

+3

@falmarri, я не согласен, они совершенно разные. Обратите внимание, что вы можете использовать их вместе. Интерфейсы предназначены для определения поведения, абстрактные классы предназначены для обеспечения функциональности * some *, но позволяют заполнять окончательные детали позже. – hvgotcodes

ответ

2

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

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

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

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

0

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

4

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

+0

Не все методы из абстрактных классов предназначены для переоценки. – chahuistle

2

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

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

1

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

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

Теперь, если вы хотите, чтобы написать свой собственный Appender, скажем, чириканье некоторые вещи, вы бы начать:

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 есть какой-то формат, а у Tweeter есть еще один, а что нет. Таким образом, вы мудры и сделать 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 решает в основном отложить ответственность за решение, требует ли этот appender макет или нет, просто используя родительский класс.

Так положить все это вместе:

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

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

Смежные вопросы