Начните с Руководства Microsoft по дизайну для разработки библиотек классов , особенно с раздела Расширяемость , где вы найдете статьи о виртуальных членах и уплотнение .
Цитата здесь:
Предпочитайте защищенную доступность публичной доступности для виртуальных участников. Открытые члены должны обеспечивать расширяемость (если требуется) путем вызова защищенного виртуального члена.
Не закрывайте классы без уважительной причины.
Тем не менее, прочтите статьи полностью.
Проектирование класса для расширяемости через наследование, в общем-то, нелегко. Когда вы что-то запечатываете, то говорите, что класс действительно не подходит для реализации наследования (может быть, вы делаете кучу низкоуровневых вещей, например, с небезопасным кодом).
Для максимальной совместимости (в математическом смысле) я предлагаю запечатывать все, что не является абстрактным классом. На самом деле, именно так реализуется алгебраический тип данных (в данном случае Sum Type) в языке (смотрите статью http://blog.lab49.com/archives/3011 для мозгового анализа).
.На мой взгляд, вы не можете предвидеть, для чего ваши пользователи в конечном итоге будут использовать это. Поэтому, как правило, хорошей идеей является НЕ запечатывать что-либо, если только нет какого-то внутреннего поведения, с которым пользователи не хотят связываться (т.е. они должны знать, что это должно быть установлено перед тем, как вы это сделаете, и т.д...)
Что касается виртуального, то вы, как правило, делаете все виртуальное, что конечный пользователь может захотеть переопределить. События значительно сократили потребность в виртуальных функциях, но все же бывают моменты, когда вам захочется сделать их виртуальными. В общем, вам нужно подумать о том, как любая функция участника может нуждаться в настройке конечным пользователем.
Controversial opinion: C# классы должны быть опечатаны по умолчанию .
Если класс не был создан для наследования и вы не продумали возможные подводные камни или не задокументировали, как правильно наследовать, то ваш класс, вполне вероятно, потерпит неудачу странными способами, если люди будут переопределять методы. Когда вы не запечатываете свой класс, вы говорите клиентам вашего класса, что это нормально, и вам придется поддерживать этот "интерфейс" вашего класса в будущем, чтобы избежать взлома клиентов, которые решат наследовать от вашего класса. Это накладывает ограничения на то, как вы можете модифицировать свой класс в будущем.
Так что по умолчанию запечатывайте классы, если только вы явно не хотите разрешить это. И если вы действительно хотите разрешить это, убедитесь, что вы документируете, какие методы должны быть переопределены, делая виртуальными, и что переопределенные методы должны сделать, чтобы гарантировать, что класс продолжает работать (например, вызов базового метода).
Во-первых, я согласен с другими ответами, которые предполагают агрессивную изоляцию всего, что не было разработано специально для расширения. Я не согласен с тем, что вам нужна причина, чтобы что-то запечатать; скорее, вам нужна причина, чтобы оставить что-то незапечатанным.
Ваш вопрос носит очень общий характер, поэтому вот общий ответ: ваша библиотека предположительно представляет собой набор функций , которые можно использовать в качестве инструментов для решения проблем пользователей. Предположительно, каждая функция в вашей библиотеке присутствует, потому что вы провели некоторое исследование, обнаружили, что существует проблема пользователя, которую необходимо решить, и решили ее за них.
Каждая из этих функций имеет определенную стоимость. Часть этих затрат осталась в прошлом - время, которое вы потратили на разработку, внедрение, тестирование, отладку и доставку кода. Некоторые из этих затрат еще впереди: обслуживание, чтение отчетов об ошибках и так далее. Существуют также более тонкие затраты, например, поддержание обратной совместимости с одной из ваших существующих функций, приведет к увеличению стоимости внедрения новой функции завтра.
Расширяемость - тоже функция . Это функция, в которой, если вы ошибаетесь, затраты почти полностью приходятся на будущее . Относитесь к нему как к любой другой функции: выясните, действительно ли эта функция нужна вашим пользователям, и окупаются ли ее преимущества за счет ее затрат. Если вы не можете четко оценить выгоду или стоимость расширяемости, небрежно реализовать ее довольно рискованно.
Объявление метода virtual подразумевает определенный контракт: ваш класс принимает возможность переопределения и ожидает этого.
Обычно есть явная причина сделать что-то виртуальным. Если сомневаетесь: не делайте этого.
А sealed как раз наоборот, вы можете заявить, что больше не хотите, чтобы он отменялся. Вторичной причиной может быть производительность, но я бы не стал использовать ее слишком быстро.
Много раз я говорил "Чёрт возьми! Почему этот класс запечатан!?", но я никогда не говорил "Боже, как бы я хотел, чтобы они запечатали этот класс!"
Есть большая вероятность, что когда-нибудь лучший программист, чем вы, захочет расширить свой класс, и будет знать, что они делают. Я думаю, что редко бывает хорошая причина для запечатывания.
У вас здесь конфликт интересов.