Как “правильно” переопределить метод базового класса?

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

1) Назовите основу. Метод (), и затем обеспечивает мою реализацию.

2) Обеспечьте мою реализацию и затем назовите основу. Метод ()

3) Просто обеспечьте мою реализацию.

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

Я возьму один пример.

public class ViewManager {
     public virtual void Customize(){
        PrepareBaseView();
     }
}

public class PostViewManager {
     public override void Customize(){
        base.Customize();
        PreparePostView();
     }
}


public class PreViewManager {
     public override void Customize(){
        PreparePreView();
        base.Customize();
     }
}


public class CustomViewManager {
     public override void Customize(){
        PrepareCustomView();
     }
}

Мой вопрос здесь состоит в том, что то, как дочерний класс мог знать (не смотря на реализацию базового класса), которые заказывают (или опция), ожидается родительским классом? Существует ли путь, которым родительский класс мог осуществить одну из трех альтернатив ко всем происходящим классам?

35
задан Manish Basantani 30 June 2010 в 20:08
поделиться

4 ответа

как дочерний класс может узнать (не обращая внимания на реализацию базового класса), какой порядок (или вариант) ожидает родительский класс?

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

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

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

public class BaseClass {
    public void Method() // Non-virtual
    {
          // Do required work

          // Call virtual method now...
          this.OnMethod();
    }

    protected virtual void OnMethod()
    { // Do nothing
    }
 }

Затем подклассы могут «переопределять» OnMethod и обеспечивать функциональность, которая возникает после работы «метода».

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

40
ответ дан 27 November 2019 в 07:20
поделиться

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

0
ответ дан 27 November 2019 в 07:20
поделиться

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

Технически эта информация должна быть включена в документацию базового объекта. Если вам абсолютно необходимо запустить какой-то код до или после кода дочернего класса, вы можете сделать следующее:

1) Создайте невиртуальную функцию в базовом классе. Назовем это MyFunction

2) Создайте защищенную виртуальную функцию в базовом классе. Назовем это _MyFunction

3) Классы-наследники расширяют метод _MyFunction.

4) Пусть MyFunction вызывает _MyFunction и запускает код, который необходимо запустить, до или после его вызова.

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

1
ответ дан 27 November 2019 в 07:20
поделиться

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

Когда я сам пишу код, я всегда старался следовать правилу, которое гласит:

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

Это взято из http://msdn.microsoft.com/en-us/library/ms229011.aspx, однако это относится к Event design, хотя я полагаю, что читал это в книге Framework Design Guidelines (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756).

Однако это явно не так, веб-формы ASP.NET, например, требуют базового вызова на Page_Load.

Короче говоря, все может быть по-разному, и, к сожалению, не существует мгновенного способа узнать это. Если я сомневаюсь, то изначально опускаю вызов.

3
ответ дан 27 November 2019 в 07:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: