На заметку!
В рамках платформ .NET/.NET Core классSystem.Object
всегда находится на вершине любой иерархии классов, являясь первоначальным родительским классом, и определяет общую функциональность для всех типов (как подробно объясняется в главе 6).В мире ООП существует еще одна форма повторного использования кода: модель включения/делегации, также известная как отношение "
Например, предположим, что снова моделируется автомобиль. Может возникнуть необходимость выразить идею, что автомобиль "имеет" радиоприемник. Было бы нелогично пытаться наследовать класс Car
Radio
(радиоприемник) или наоборот (ведь Car
не "является" Radio
). Взамен есть два независимых класса, работающих совместно, где класс Car
создает и открывает доступ к функциональности класса Radio
:class Radio
{
public void Power(bool turnOn)
{
Console.WriteLine("Radio on: {0}", turnOn);
}
}
class Car
{
// Car 'имеет' Radio.
private Radio myRadio = new Radio();
public void TurnOnRadio(bool onOff)
{
// Делегировать вызов внутреннему объекту.
myRadio.Power(onOff);
}
}
Обратите внимание, что пользователю объекта ничего не известно об использовании классом Car
Radio
:// Call is forwarded to Radio internally.
Car viper = new Car();
viper.TurnOnRadio(false);
Роль полиморфизма
Последним основным принципом ООП является
Выражаясь кратко,
Чтобы увидеть полиморфизм в действии, давайте предоставим некоторые детали иерархии фигур, показанной на рис. 5.3. Предположим, что в классе Shape
Draw()
, не принимающий параметров. С учетом того, что каждой фигуре необходимо визуализировать себя уникальным образом, подклассы вроде Hexagon
и Circle
могут переопределять метод Draw()
по своему усмотрению (см. рис. 5.3).После того как полиморфный интерфейс спроектирован, можно начинать делать разнообразные предположения в коде. Например, так как классы Hexagon
Circle
унаследованы от общего родителя (Shape
), массив элементов типа Shape
может содержать любые объекты классов, производных от этого базового класса. Более того, поскольку класс Shape
определяет полиморфный интерфейс для всех производных типов (метод Draw()
в данном примере), уместно предположить, что каждый член массива обладает такой функциональностью.Рассмотрим следующий код, который заставляет массив элементов производных от Shape
Draw()
:Shape[] myShapes = new Shape[3];
myShapes[0] = new Hexagon();
myShapes[1] = new Circle();
myShapes[2] = new Hexagon();
foreach (Shape s in myShapes)
{
// Использовать полиморфный интерфейс!
s.Draw();
}
Console.ReadLine();
На этом краткий обзор основных принципов ООП завершен. Оставшийся материал главы посвящен дальнейшим подробностям поддержки инкапсуляции в языке С#, начиная с модификаторов доступа. Детали наследования и полиморфизма обсуждаются в главе 6.