Есть пара вещей, которые вы не рассматриваете.Существуют абстрактные классы и абстрактные методы.Абстрактные классы не могут быть созданы напрямую, они, так сказать, просто шаблоны.Абстрактные методы могут быть определены только в классе 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
}
}
}
В любом случае, мои два цента.