Вход/Регистрация
ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
вернуться

Троелсен Эндрю

Шрифт:

 // Вызов внутренне передается Radio.

 Car viper = new Car;

 viper.TurnOnRadio(true);

}

Полиморфизм

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

Чтобы проиллюстрировать понятие полиморфизма, снова используем иерархию форм. Предположим, что класс Shape определил метод Draw, не имеющий параметров и не возвращающий ничего. С учетом того, что визуализация для каждой формы оказывается уникальной, подклассы (такие как Hexagon и Circle) могут переопределить соответствующий метод так, как это требуется для них (рис. 4.4).

Рис. 4.4. Классический полиморфизм

После создания полиморфного интерфейса можно использовать различные предположения, касающиеся программного кода. Например, если Hexagon и Circle являются производными от одного общего родителя (Shape), то некоторый массив типов Shape может содержать любой производный класс. Более того, если Shape определяет полиморфный интерфейс для всех производных типов {в данном примере это метод Draw, то можно предположить, что каждый член в таком массиве имеет эти функциональные возможности. Проанализируйте следующий метод Main, в котором массиву типов, производных от Shape, дается указание визуализировать себя с помощью метода Draw.

static void Main(string [] args) {

 // Создание массива элементов, производных от Shape.

 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;

}

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

Первый принцип: сервис инкапсуляции C#

Понятие инкапсуляции отражает общее правило, согласно которому поля данных объекта не должны быть непосредственно доступны из открытого интерфейса. Если пользователь объекта желает изменить состояние объекта, то он должен делать это косвенно, с помощью методов чтения (get) и модификации (set). В C# инкапсуляция "навязывается" на уровне синтаксиса с помощью ключевых слов public, private, protected и protected internal, как было показано в главе 3. Чтобы проиллюстрировать необходимость инкапсуляции, предположим, что у нас есть следующее определение класса.

// Класс с одним общедоступным полем.

public class Book {

 public int numberOfPages;

}

Проблема общедоступных полей данных заключается в том, что такие элементы не имеют никакой возможности "понять", является ли их текущее значение действительным с точки зрения "бизнес-правил" данной системы. Вы знаете, что верхняя граница диапазона допустимых значений для int в C# очень велика (она равна 2147483647). Поэтому компилятор не запрещает следующий вариант присваивания.

// М-м-м-да…

static void Main(stting[] args) {

 Book miniNovel = new Book;

 miniNovel.numberOfPages = 30000000;

}

Здесь нет перехода за границы допустимости для данных целочисленного типа, но должно быть ясно, что miniNovel ("мини-роман") со значением 30000000 для numberOfPages (число страниц) является просто невероятным с практической точки зрения. Как видите, открытые поля не обеспечивают проверку адекватности данных. Если система предполагает правило, по которому мини-роман должен содержать от 1 до 200 страниц, будет трудно реализовать это правило программными средствами. В этой связи открытые поля обычно не находят места на уровне определений классов, применяемых для решения реальных задач (исключением являются открытые поля, доступные только для чтения).

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

• Определение пары традиционных методов чтения и модификации данных.

• Определение именованного свойства.

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

  • Читать дальше
  • 1
  • ...
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: