Совет дизайна - Когда использовать “виртуальный” и “изолированный” эффективно [закрытый]

31
задан Yvette Colomb 6 December 2018 в 01:43
поделиться

8 ответов

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

Цитата здесь:

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

  • Не закрывайте классы без уважительной причины.

  • Не объявляйте защищенные или виртуальные члены для запечатанных типов.
  • Считайте уплотнительные элементы, которые вы игнорируете.

Тем не менее, прочтите статьи полностью.

25
ответ дан 27 November 2019 в 21:56
поделиться

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

Для максимальной совместимости (в математическом смысле) я предлагаю запечатывать все, что не является абстрактным классом. На самом деле, именно так реализуется алгебраический тип данных (в данном случае Sum Type) в языке (смотрите статью http://blog.lab49.com/archives/3011 для мозгового анализа).

.
3
ответ дан 27 November 2019 в 21:56
поделиться

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

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

7
ответ дан 27 November 2019 в 21:56
поделиться

Controversial opinion: C# классы должны быть опечатаны по умолчанию .

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

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

3
ответ дан 27 November 2019 в 21:56
поделиться

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

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

Каждая из этих функций имеет определенную стоимость. Часть этих затрат осталась в прошлом - время, которое вы потратили на разработку, внедрение, тестирование, отладку и доставку кода. Некоторые из этих затрат еще впереди: обслуживание, чтение отчетов об ошибках и так далее. Существуют также более тонкие затраты, например, поддержание обратной совместимости с одной из ваших существующих функций, приведет к увеличению стоимости внедрения новой функции завтра.

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

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

Объявление метода virtual подразумевает определенный контракт: ваш класс принимает возможность переопределения и ожидает этого.

Обычно есть явная причина сделать что-то виртуальным. Если сомневаетесь: не делайте этого.

А sealed как раз наоборот, вы можете заявить, что больше не хотите, чтобы он отменялся. Вторичной причиной может быть производительность, но я бы не стал использовать ее слишком быстро.

4
ответ дан 27 November 2019 в 21:56
поделиться

Много раз я говорил "Чёрт возьми! Почему этот класс запечатан!?", но я никогда не говорил "Боже, как бы я хотел, чтобы они запечатали этот класс!"

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

6
ответ дан 27 November 2019 в 21:56
поделиться

У вас здесь конфликт интересов.

  • Если вы хотите облегчить тестирование кода для ваших пользователей (например, для разработки на основе тестирования), ваши пользователи должны иметь возможность высмеивать ваш класс.
    • Поэтому все методы ect должны быть виртуальными или у вас должен быть интерфейс, который вы реализуете и который содержит все методы.
  • Однако если вы хотите, чтобы было ясно, какой контракт вы предоставляете любым подклассам, которые могут создать ваши пользователи, то вам следует придерживаться рекомендаций Microsoft.
    • Не делайте члены виртуальными, если у вас нет веских причин для этого, и вы знаете обо всех затратах, связанных с разработкой, тестированием и поддержкой виртуальных членов. Жаль, что нет способа пометить виртуальный метод, чтобы сказать, что вы не ожидаете, что клиентский код сможет его реализовать, кроме как с помощью mocking.
2
ответ дан 27 November 2019 в 21:56
поделиться
Другие вопросы по тегам:

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