Бесплодные классы
В С# есть ключевое слово sealed, позволяющее описать класс, от которого, в противоположность абстрактному, наследовать запрещается:
sealed class Spirit {
// class Monster : Spirit { ... } ошибка!
Большинство встроенных типов данных описано как sealed. Если необходимо использовать функциональность бесплодного класса, применяется не наследование, а вложение, или включение: в классе описывается поле соответствующего типа.
Вложение классов, когда один класс включает в себя поля, являющиеся классами, является альтернативой наследованию при проектировании. Например, если есть объект «двигатель», а требуется описать объект «самолет», логично сделать двигатель полем этого объекта, а не его предком.
Поскольку поля класса обычно закрыты, возникает вопрос, как же пользоваться методами включенного объекта. Общепринятый способ состоит в том, чтобы описать метод объемлющего класса, из которого вызвать метод включенного класса. Такой способ взаимоотношений классов известен как модель включения-делегирования. Пример приведен в листинге 8.4.
Листинг 8.4.Модель включения-делегирования
using System;
namespace ConsoleApplication1
{
class Двигатель
{
public void Запуск()
{
Console.WriteLine("вжжжж!!");
}
}
class Самолет
{
public Самолет()
{
левый = new Двигатель();
правый = new Двигатель();
}
public void Запустить_двигатели()
{
левый.Запуск();
правый.Запуск();
}
Двигатель левый, правый;
}
class Class1
{
static void Main()
{
Самолет АН24_1 = new Самолет();
АН24_1.Запустить_двигатели();
}
}
}
Результат работы программы:
вжжжж!! вжжжж!!
В методе Запустить_двигатели запрос на запуск двигателей передается, или, как принято говорить, делегируется вложенному классу.
отличие от наследования, когда производный класс «является» (is а) разностью базового, модель включения-делегирования реализует отношение имеет» (has а). При проектировании классов следует выбирать модель, наиболее точно отражающую смысл взаимоотношений классов, например, моделируемых объектов предметной области.