Pull to refresh

Comments 13

Для большинства ответивших на данный момент «А что это?»
sealed — модификатор который запрещает наследование.

То есть от класс с таким атрибутом нельзя пронаследовать новый класс.
То же и с методами. Например если у вас есть virtual метод, то пометив его в одном из унасловаднных классов как sealed override в классах унаследованных от этого данный метод уже нельзя будет переопределить.

Лично я считаю что к таком стоит прибегать лишь в очень редких случаях, и в рабочих проектах применять пока не приходилось.
Бывают случаи, когда базовый класс предоставляет слишком общий интерфейс, который необходимо детализировать в наследнике. Вот пример:
public abstract class PageBase
{
  protected abstract void RenderPage();
}

public abstract class MainPageBase
{
  protected override sealed void RenderPage()
  {
    RenderHeader();
    RenderBody();
    RenderFooter();
  }

  protected abstract void RenderHeader();
  protected abstract void RenderBody();
  protected abstract void RenderFooter();
}


(Пример чисто гипотетический, на имена методов можно не смотреть.)

В данном случае модификатор sealed необходим, иначе кто-то может переопределить метод RenderPage() в наследнике MainPageBase и не вызвать в нем методы RenderHeader(), RenderBody() и RenderFooter().
Согласен, пример удачный.
Вообще с использованием этого модификатора главное не нарушить баланс между подстиланием соломки и ограничением возможностей последующего расширения.
Ведь если в одном случае это может помочь начинающему разработчику не сломать логику, то в случае если человек знает как именно хочет расширить ваш класс, или немножко подправить логику — то ему придется создавать лишний код, который может даже дублировать ваш.
Применяю и стараюсь как можно чаще. Важно: Не программирую библиотеки классов.
А чем продиктовано это стремление «как можно чаще»?
Стремление у меня не продиктовано. Я просто убеждён, что это заставляет коллег по проекту чаще и большие задумываться о том, почему они собираются использовать наследование. В подавляющем большинстве случаев у нас наследование это неоправданное усложнение программы. Если мы приходим к тому, что наследование — необходимость в конкретном случае, модификатор sealed убирается. Это не вызывает больших проблем, т.к., повторю, мы не пишем библиотек классов, которые трудно обновлять.
Я просто убеждён, что это заставляет коллег по проекту чаще и большие задумываться о том, почему они собираются использовать наследование.

Я в свое время работал в команде с человеком, который ставил sealed практически всегда и везде, ну если только класс не абстрактный. Через какое-то время привело это к обратному эффекту — т.к. все привыкли, что товарищ ставит sealed просто по механике, без особого умысла, привязанного к конкретному случаю, то просто удаляли этот модификатор считали нужным пронаследоваться. По этому и спросил.
Это печально, конечно. Но чем больше я занимаюсь разработкой ПО, тем больше я понимаю, что при кодировании надо думать над каждой единицей кода (т.е. даже не строкой). И если кто-то проигнорировал мою подсказку, что я не увидел у класса X потенциальных потомков и вообще не хотел бы, чтобы они были, то этот человек сам взял на себя ответственность за убранный модификатор.

Иными словами, фраза
то просто удаляли этот модификатор считали нужным пронаследоваться
вызывает у меня нехорошие мысли про этих разработчиков. «Просто удаляли» для меня равно «бездумно удаляли». Я себе стараюсь не позволять такого, хотя, наверняка, часто не замечаю этого. Особенно, когда устал.

Мой опыт советует мне избегать наследования при возможности, т.к. я сам с трудом поддерживаю такого рода код, написанный мной же. Так почему мне быть уверенным, что кто-то другой сможет сделать это легко и правильно?
Тот же Gendarme, если мне память не изменяет, утверждает, что использование модификатора sealed улучшает производительность, например.
Никак не могу вспомнить автора (кто-то из CS классиков). Описывая случаи применения модификатора sealed, он советовал использовать его во всех случаях, когда класс специально не задумывается, как базовый для чего-то ещё. Я, вообщем-то, согласен с этим советом — огромные иерархии наследования сложно поддерживать, при этом можно получить ошибку в неожиданном месте как раз из-за того, что автор базового класса не предполагал его на самом деле базовым, а просто забыл добавить sealed.
Рад, что я не один такой. :) На самом деле, всю остроту проблемы я прочувствовал, когда было трудно поддерживать даже неглубокую иерархию (всего три уровня). В более сложных случаях, имхо, надо быть гуру, чтобы объектная модель получилась удобная и, главное, правильная, устойчивая.

А вот замечать, что класс не следует делать закрытым, мне ещё предстоит. Пока руководствуюсь простым — по-умолчанию все классы запечатаны, а все члены класса — private. Если потребуется, открою. Если бы я разрабатывал библиотеку типов, то такой подход «не прокатил» бы.
Да, почти всегда на классах. Не знал, что его можно использовать на методах и свойствах.
У меня дефолтный шаблон класса делает `internal sealed`.
Sign up to leave a comment.

Articles