Тема 7. Архитектура и возможности семейства языков высокого уровня

advertisement
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
Тема 7. Архитектура и возможности семейства языков
высокого уровня
Цель
Изучить
принципы
объектно-ориентированных
языков
программирования: инкапсуляцию, наследование, полиморфизм.
Задачи
1. Рассмотреть
три
основных
принципа
объектноориентированных языков программирования.
2. Описать структуру классов в объектно-ориентированных
языках программирования на примере Visual Basic.NET.
3. Выполнить реализацию свойств класса в VB.NET.
Оглавление
Тема 7. Архитектура и возможности семейства языков высокого
уровня ...................................................................................................... 1
Базовые принципы объектно-ориентированного
программирования ................................................................................. 1
Определение классов в Visual Basic.NET ........................................... 4
Свойства классов в Visual Basic.NET .................................................. 6
Выводы .................................................................................................. 11
Вопросы для самопроверки ............................................................... 11
Литература ............................................................................................. 12
Базовые принципы объектно-ориентированного
программирования
Язык Visual Basic.NET можно считать новым членом сообщества
объектно-ориентированных языков программирования, к самым
распространенным из которых относятся Java, C++, Object Pascal и (с
некоторыми допущениями) Visual Basic 6.0 (VB является языком,
умеющим работать с объектами). В любом объектно-ориентированном
языке программирования обязательно реализованы три важнейших
(базовых) принципа объектно-ориентированного программирования:
 Инкапсуляция: как объекты прячут свое внутреннее
устройство;
 Наследование: как в этом языке поддерживается повторное
использование кода;
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
 Полиморфизм: как в этом языке реализована поддержка
выполнения нужного действия в зависимости от типа
передаваемого объекта?
Все базовые принципы в полной мере реализованы в языках,
принадлежащих к платформе .NET, в том числе и в языке Visual
Basic.NET.
ИНКАПСУЛЯЦИЯ
Первый «столп» объектно-ориентированного программирования – это
инкапсуляция. Так называется способность прятать детали
реализации объектов от пользователей этих объектов. Например,
предположим, что мы создали класс с именем DBReader (для работы
с базой данных); в классе определено два главных метода: Open() и
Close().
Класс DBReader скрывает за счет инкапсуляции подробности
открытия и закрытия баз данных
Dim f As New DBReader
f.Open("C:\foo.mdb")
Выполняем с базой данных нужные нам действия
f.Close()
Наш класс DBReader инкапсулирует внутренние подробности того, как
именно он обнаруживает, загружает, выполняет операции и, в конце
концов, закрывает файл данных.
За счет инкапсуляции программирование становится проще: вам нет
необходимости беспокоиться об огромном количестве строк кода,
которые выполняют свою задачу, подробности, скрыты от вас. Все,
что вам необходимо – создать экземпляр нужного класса и передать
ему необходимые сообщения (типа «открыть файл с именем
foo.mdb»).
С философией инкапсуляции тесно связан еще один принцип –
сокрытие всех внутренних данных (то есть переменных-членов)
класса. В идеале все внутренние переменные-члены класса должны
быть определены как Private. В результате обращение к ним из
внешнего мира будет возможно только при помощи открытых
функций-членов. Такое решение, помимо всего прочего, защищает вас
от возможных ошибок, поскольку открытые данные очень просто
повредить.
НАСЛЕДОВАНИЕ: отношения «быть» и «иметь»
Следующий столп объектно-ориентированного программирования –
наследование. Под ним понимается возможность создавать новые
определения классов на основе существующих. В сущности,
наследование
позволяет
вам
расширить
возможности,
унаследованные от базового класса, в собственном производном
классе.
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
Простой пример реализации такого подхода представлен на рис. 7.1.
Как вы помните, на вершине любой иерархии в .NET всегда находится
базовый класс Object. В нашей ситуации возможности этого класса
вначале дополняются возможностями, привнесенными классом
Shape. Речь идет о свойствах, методах и событиях, которые являются
общими для всех геометрических фигур (shape). Класс Hexagon
(шестиугольник), производный от Shape, дополняет возможности
предыдущих
двух
базовых
классов
своими
собственными
уникальными свойствами.
Object
Shape
Hexagon
Рис. 7.1. Отношение «быть»
Диаграмму классов, представленную на рис. 7.1, можно прочесть
следующим образом: «Шестиугольник есть геометрическая фигура,
которая есть объект». Когда ваши классы связываются друг с другом
отношениями наследования, это означает, что вы устанавливаете
между ними отношение типа «быть» (is-a). Такой тип отношения
называется также классическим наследованием.
ПОЛИМОРФИЗМ
Последний,
третий
столп
объектно-ориентированного
программирования – это полиморфизм. Можно сказать, что этот
термин определяет возможности, заложенные в языке, по
интерпретации связанных объектов одинаковым образом. При
использовании полиморфизма вы можете определить в базовом
классе набор членов, которые могут быть замещены в производном
классе. При замещении в производных классах членов базового
класса эти производные классы будут по-разному реагировать на одни
и те же обращения.
Для примера мы вновь обратимся к нашей иерархии геометрических
фигур. Предположим, что в классе Shape (геометрическая фигура)
определена функция Draw() – рисование, которая не принимает
параметров и ничего не возвращает. Поскольку геометрические
фигуры бывают разными, и каждый тип фигуры потребует изображать
своим собственным уникальным способом, скорее всего, нам
потребуется в производных классах (таких как Hexagon –
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
шестиугольник и Circle – окружность) создать свой собственный метод
Draw(), заместив им метод Draw() базового класса (рис. 7.2).
Классический полиморфизм позволяет определять возможности всех
производных классов при создании базового класса. Например, в
нашем случае вы можете быть уверены, что метод Draw() в том или
ином варианте присутствует в любом классе, производном от Shape. К
достоинствам классического полиморфизма можно отнести также и то,
что во многих ситуациях вы сможете избежать создания
повторяющихся методов для выполнения схожих операций (типа
DrawCircle(), DrawRectangle(), DrawHexagon() и так далее).
Object
Shape
Draw()
+ Draw ()
Hexagon
Draw()
+ Draw ()
Circle
Draw()
+ Draw ()
Рис. 7.2. Полиморфизм
Определение классов в Visual Basic.NET
Мы используем ключевое слово Class для определения класса. Класс
может содержать данные и методы, выполняющие действия. В
следующей таблице представлены виды-членов, которые мы можем
определить в классе:
Вид данных-членов Описание
Переменная
Переменная – это часть данных, которая
хранится в объектах класса. Мы можем также
использовать ключевое слово Shared для
описания
данных,
которые
будут
использоваться всеми объектами данного
класса.
Свойство
Свойство
похоже
на
переменную,
за
исключением того, что его значение должно
возвращаться и устанавливаться с помощью
методов Get и Set класса.
Константа
Константа – это значение, доступное только для
чтения и используемое всеми объектами
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
класса.
Событие
Событие – это сообщение, которое объект
может послать другим заинтересованным в
этом объектам. В .NET Framework мы
используем терминологию «источник события»
для обозначения объекта, который может
генерировать событие, и «получатель события»
для обозначения объекта, который принимает
события.
Вид функции-члена Описание
Метод
Метод – это функция или процедура, которая
предоставляет некоторую функциональность
объектам
класса.
Мы
можем
также
использовать ключевое слово Shared для
определения методов, которые относятся к
самому классу, а не к конкретным его объектам.
Конструктор
Конструктор – это метод, предназначенный для
инициализации. Каждый раз, когда мы создаем
объект определенного класса, вызывается
конструктор, который инициализирует объект
его начальным значением (состоянием).
Завершающий
Класс может иметь один завершающий метод,
метод
называемый Finalize(). CLR вызывает этот
метод непосредственно перед тем, как
уничтожить объект с помощью процесса уборки
мусора. Это подходящее место для выполнения
операций, которые необходимо осуществить
перед удалением объекта.
Определение области видимости для классов очень важно в больших
системах, где число классов достигает порой нескольких тысяч.
Целью определения области видимости является необходимость
ограничить видимость настолько, насколько это возможно, но не
более того. При сокрытии классов от остальных частей системы она
становится менее связанной и более простой в сопровождении.
Рассмотрим способы задания области видимости классов.
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
Class MyClass1
End Class
Класс MyClass1 неявным образом объявлен доступным для всех
сборок; это означает, что к нему можно осуществлять доступ из
любого другого кода и из любой сборки.
Public Class MyClass2
End Class
Класс MyClass2 явным образом объявлен доступным для всех сборок.
Friend Class MyClass3
End Class
Класс MyClass3 виден в текущей сборке, но не виден извне.
Private Class MyClass4
End Class
Класс MyClass4 виден только в области его объявления. Классы,
объявленные с помощью ключевого слова Private, используются для
реализации логики внутри класса, при этом, не предоставляя этой
логики другим частям приложения.
Свойства классов в Visual Basic.NET
Свойство ведет себя, с точки зрения программиста, использующего
класс, как порция данных класса. Пользователи класса могут
обращаться к имени свойства напрямую, как будто класс на самом
деле имеет элемент с таким именем. Однако внутри класса свойство
реализуется как пара процедур свойства: процедура Get свойства,
получающая значение свойства, и процедура Set свойства,
устанавливающая
значение
свойства.
Процедуры
свойства
выполняют всю обработку, требуемую для получения и задания
значения свойства.
Свойства являются важной частью разработки нашего класса.
Например, следующая диаграмма показывает небольшой фрагмент
модели объекта, представляющего человека, работающего в
компании. Используется нотация UML (Unified Modeling Language)
(рис. 7.3).
Person
- Name : System.String
- Age
: System.UInt32
+ Pay () : System.UInt32
Company
0..*
0..1
- CompanyNumber : System.UInt32
- CompanyName
: System.String
+ HirePerson () : Boolean
Рис. 7.3. Диаграмма классов
Класс Person имеет два атрибута с именами Name и Age. Когда мы
реализуем этот класс в VB.NET мы должны решить, как представить
Name и Age в нашем коде. Одним из вариантов может быть
определение Name и Age как Private-полей класса Person; однако это
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
не позволит обращаться к информации ниоткуда, кроме самого
класса. Можно объявить Name и Age как Public-поля, но тогда
нарушается принцип инкапсуляции для класса Person: открывается
доступ к данным, которые при таком объявлении могут быть
прочитаны и изменены любой другой частью программы – сокрытие
данных полностью разрушено.
Свойства класса позволяют решить эту проблему. Свойства
позволяют предоставлять данные клиентскому коду и, в то же время,
сохранять инкапсуляцию того, как данные представлены внутри
класса. Например, мы можем написать проверочный код в процедуре
Set свойства для того, чтобы быть уверенными в том, что
пользователь не присвоит свойству недопустимое значение.
Аналогично, мы можем выполнить вычисления в процедуре Get
свойства для пересчета значения свойства по требованию.
Мы можем опустить процедуру Get или Set для свойства:
 Если мы опускаем процедуру Set свойства и используем
ключевое слово ReadOnly при описании свойства, то,
очевидно, оно будет свойством только для чтения. Это может
быть полезно для свойств, которые должны быть пересчитаны
каждый раз, когда они используются, например, число дней,
которые сотрудник работает в компании. Другим случаем
использования свойств только для чтения является «поздняя»
инициализация, при которой мы не присваиваем свойству
никакого значения до тех пор, пока оно не будет
непосредственно запрошено клиентским кодом. Это является
очень полезной возможностью при оптимизации приложения,
которое выполняет большое количество запросов к базе
данных.
 Если мы опускаем процедуру Get свойства и используем
ключевое слово WriteOnly при описании свойства, то свойство
становится только для записи; оно может быть полезно, если
класс имеет внутренний конфигурирующий флаг, который мы
хотим выставлять, но никогда не хотим проверять. Однако,
создание
свойства,
доступного
для
чтения,
редко
используется.
CLR в .NET Framework поддерживает два различных вида свойств:
Скалярные свойства. Скалярное свойство представляет одно
значение. Значение может быть простым, таким как Integer или String,
или сложным, таким как объект типа DateTime или Color.
Индексированные
свойства.
Индексированное
свойство
представляет коллекцию (набор) значений. Клиентский код использует
синтаксис массива для доступа к конкретным значениям из этой
коллекции.
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
Начнем рассмотрение скалярных свойств на примере свойства Name
класса Person. Класс Person имеет поле с именем MName, которое
содержит имя человека. Это поле объявлено как Private для
запрещения доступа к нему непосредственно из клиентского кода. Как
мы уже несколько раз повторяли, одной из наиболее важных целей
объектно-ориентированной
разработки
является
сохранение
инкапсуляции класса. Другими словами: «Не объявляйте полей
Public».
Public Class Person
Private MName As String
Public Property Name() As
String
Get
Return MName
End Get
Set(ByVal Value As String)
MName = Value
End Set
End Property
End Class
Следующий фрагмент кода показывает, как использовать свойство
Name, определенное в классе Person
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim APerson As New Person
APerson.Name = TextBox1.Text
MsgBox(APerson.Name)
End Sub
Рассмотрим описание свойств для чтения/записи, только для чтения и
только для записи. Свойство Name в предыдущем примере являлось
свойством для чтения/записи. Определим свойство только для чтения
на примере информации о дне рождения человека, а свойство только
для записи на примере свойства EmailAlias для установки имени email-адреса человека. Имя e-mail-адреса человека представляет
первую часть e-mail-адреса сотрудника фирмы, стоящую перед
именем домена. Это имя может быть изменено, но к нему никогда
нельзя осуществить доступ (вместо этого, клиентская программа
получает полный e-mail-адрес). Свойство EmailAddress для получения
полного e-mail адреса. E-mail адрес формируется каждый раз при
обращении к нему путем добавления имени домена компании к имени
адреса человека.
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
Public Class Person
Private MName As String
Private MDob As DateTime
Private MEmailAlias As String
Public Sub New(ByVal name As String, ByVal Dob As DateTime)
MName = name
MDob = Dob
End Sub
Public Property Name() As String
Get
Return MName
End Get
Set(ByVal Value As String)
MName = Value
End Set
End Property
Public ReadOnly Property DOB()
As DateTime
Get
Return MDob
End Get
End Property
Public WriteOnly Property
EmailAlias() As String
Set(ByVal Value As String)
MEmailAlias = Value
End Set
End Property
Public ReadOnly Property
EmailAddress() As String
Get
Return MEmailAlias &
"@MyCompany.com"
End Get
End Property
End Class
Работа со свойствами только чтения или записи выглядит, например,
следующим образом:
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim APerson As New Person("Петров В.Н.", New DateTime(1978, 7, 2))
TextBox1.Text = APerson.Name
TextBox2.Text = APerson.DOB.ToLongDateString
APerson.EmailAlias = "Petrov"
TextBox3.Text = APerson.EmailAddress
End Sub
Разделяемое свойство (Shared-свойство) представляет собой часть
информации, общей для всего класса, которую мы хотим представить
как часть класса, а не как часть конкретного экземпляра класса.
Клиентский код получает доступ к разделяемым свойствам через
класс, а не через экземпляр этого класса. Следующий пример
показывает, как определить разделяемое свойство Domain для
представления имени домена, которое используется как часть e-mailадреса человека.
В коде класса появится еще один фрагмент кода:
Public Class Person
Private Shared MDomain As String
Public Shared Property Domain() As String
Get
Return MDomain
End Get
Set(ByVal Value As String)
MDomain = Value
End Set
End Property
Public ReadOnly Property EmailAddress() As String
Get
Return MEmailAlias & "@" &
MDomain
End Get
End Property
Воспользоваться этим
разделяемым свойством можно,
например, таким образом:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim APerson As New Person("Петров В.Н.", New DateTime(1978, 7, 2))
Person.Domain = "MyCoolSite.com"
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
APerson.EmailAlias = "Petrov"
TextBox1.Text = APerson.EmailAddress
End Sub
Обратите внимание на следующие моменты в этом примере:
 Свойство Domain разделяемое.
 Свойство EmailAddress использует имя домена для генерации
полного E-mail-адреса человека.
 Процедура Button1_Click устанавливает свойство Domain,
используя имя класса Person, а не имя экземпляра класса
APerson.
Выводы
Языки программирования, так же как и естественные языки общения,
сильно влияют на способ мышления человека. Есть очень много
интересных исследований лингвистов по этому поводу. Например,
работа Р. Логана «Эффект алфавита» объясняет, почему наука и
логика возникли на Западе, а развитая технология – в Китае.
Объектно-ориентированное программирование – это стиль мышления,
а не технология. Если среда разработки не позволяет использовать ту
или иную технологию, то программист бессилен что-нибудь изменить,
но никто не может запретить ему мыслить объектами. ООП-стиль
можно реализовать и на языке С, и на QuickBasic, и даже на языке
Ассемблера. Проблема в том, что эти языки не стимулируют
объектно-ориентированный
стиль
мышления.
Объектноориентированные
языки
программирования
непосредственно
поддерживают основные принципы ООП, такие как создание объектов
на основе классов, использование наследования, применение
полиморфизма.
При
использовании
других
(не
объектноориентированных) языков программирования приходится не только
думать об архитектуре проекта, но и «сражаться» с языком, который
не позволяет наследовать классы друг от друга или создавать
сложные объекты. Итак, главная задача объектно-ориентированного
языка – облегчить разработку проекта в рамках парадигмы ООП.
Вопросы для самопроверки
1. Как вы считаете, не находятся ли в противоречии процессы
инкапсуляции, как процесса сокрытия кода реализации свойств и
методов класса, и полиморфизма, как процесса изменения,
расширения кода свойств и методов классов наследников?
2. Если при описании класса не было объявлено области его
видимости, то какую область видимости такой класс будет иметь
по умолчанию?
3. Чем отличаются атрибуты класса от свойств класса?
МЕЖДУНАРОДНЫЙ БАНКОВСКИЙ ИНСТИТУТ
INTERNATIONAL BANKING INSTITUTE
4. Для чего применяются свойства с ключевым словом ReadOnly?
5. Для чего применяются свойства с ключевым словом WriteOnly?
6. В чем отличие скалярных свойств класса от индексированных
свойств класса?
7. Для чего используются разделяемые Shared-свойства класса? В
чем состоит особенность их использования?
1.
2.
3.
4.
Литература
Ольсен Э., Эллисон д., Спир Дж. Visual Basic .NET. Разработка
классов. Справочник/Практ. Пособ./Пер. с англ. — М.
Издательство «СП ЭКОМ», 2006. – 416 с. ил.
Троелсен Э. C# и платформа .NET. Библиотека программиста —
СПб.: Питер, 2006 — 796 с.: ил.
Объектно-ориентированное
программирование
в
Visual
Basic.NET. Библиотека программиста / Д. Кларк. – СПб.: Питер,
2005. – 352 с.: ил.
Visual Basic.NET: учебный курс/ В.Долженков, М.Мозговой. —
СПб.: Питер, 2005. – 465 с,: ил.
Download