Объектно-ориентированное программирование (ООП) является основой разработки программ на языке Swift. Мы уже неоднократно встречались с одним фундаментальным для данного языка правилом «всё — это объект». Пришло время приступить к изучению наиболее интересных и сложных механизмов, доступных в Swift. Данная глава расскажет вам о наиболее важных терминах и понятиях объектно-ориентированного программирования.
Возможно, вы изучали ООП в прошлом на уроках информатики в школе или в институте, а может, самостоятельно. В таком случае вы, конечно же, знаете три постулата ООП: инкапсуляция, наследование и полиморфизм. Я настоятельно советую вам потратить свободное время и дополнительно разобраться с ними так как в связи с ограничением на объем книги в основном будет показана практическая сторона ООП. Но в данном случае общая теоретическая база крайне важна.
Основные конструкции, с которыми мы будем работать в этой части, — перечисления, структуры и классы. Открою вам один удивительный секрет: вы уже давно работаете с некоторыми из них! Например, тот же целочисленный тип данных Int — это структура.
Перечисления, структуры и классы имеют свои особенности и возможности, и именно они делают Swift таким, какой он есть. Тем не менее у них есть одно общее базовое свойство — для них могут быть созданы экземпляры. Когда вы самостоятельно определяете объектный тип (перечисление, структуру или класс), вы лишь cоздаете новый тип данных. В свою очередь, создание экземпляра объектного типа — это создание хранилища (переменной или константы) для данных определенного типа. Так, например, упомянутый ранее тип Int — это структура, а переменная myInteger, хранящая в себе значение этого типа, — экземпляр данной структуры.
ПРИМЕЧАНИЕ Несмотря на то что мы много раз говорили об объектах, правильнее называть их экземплярами.
Объектами в других языках программирования назывались экземпляры классов, а экземпляры структур и перечислений — просто экземплярами. Так как функционал структур, перечислений и классов очень близок по своим возможностям, в Swift соответствующие объекты называются просто экземплярами.
Ранее в книге мы говорили об экземплярах и даже приводили несколько примеров их реализации. Помните проведенные ранее аналогии между категорией и протоколом, стандартом и типом данных, конкретной реализацией и экземпляром (табл. 21.1)?
Таблица 21.1. Соответствия между понятиями
Пример из реального мира | Понятия реального мира | Понятия в Swift | Пример из Swift |
Автомобили с бензиновым двигателем | Категория | Протокол | SignedNumber (требует, чтобы тип данных обеспечивал хранение как положительных, так и отрицательных чисел) |
Kia Rio | Стандарт (модель) | Тип данных | Int |
Kia Rio VIN XW122FX849 | Конкретная реализация | Экземпляр | 2 (целое число типа Int) |
ПРИМЕЧАНИЕ Данная таблица уже рассматривалась в книге ранее в главе 7.
Вы уже умеете создавать и использовать экземпляры конкретных типов данных. В этой части вы научитесь создавать сперва сами типы данных, а потом и протоколы. Вы можете использовать все свое воображение, создавая типы данных. А используются для этого именно классы, структуры и перечисления.
ПРИМЕЧАНИЕ Приведенная выше схема «Протокол — Тип данных — Экземпляр» (см. табл. 21.1) является «идеальной», но при этом совершенно не обязательно реализовывать протоколы, так как типы данных могут быть созданы напрямую. Обо всем этом вы узнаете из книги.
Рассмотрим простой пример.
Представьте, что определен класс Automobile (автомобиль). Этот класс является типом данных. Данный «Автомобиль» является не каким-то конкретным автомобилем, а лишь конструкцией, с помощью которой можно определить этот конкретный автомобиль. Если создать переменную типа Automobile, то в результате мы получим экземпляр этого класса (рис. 21.1).
Рис. 21.1. Класс и его экземпляр
Сам класс на рисунке не имеет выраженных черт, так как еще неизвестно, какой же определенный объект реального (или нереального) мира он будет определять. Но когда создана переменная bmw типа Automobile, мы уже знаем, что с экземпляром в этой переменной мы будем работать как с реальным авто марки BMW:
bmw: Automobile = Automobile()
Такой тип данных может наделять экземпляр какими-либо характеристиками. Для класса Automobile это могли бы быть марка, модель, цвет, максимальная скорость, объем двигателя и т.д. Характеристики объектных типов называются свойствами, с ними мы встречались неоднократно. Для переменной bmw значения этих свойств могли бы быть следующими:
bmw.brand = "BMW"
bmw.type = "X3"
bmw.maxSpeed = 210
bmw.engineCapacity = 1499
Свойства представляют собой хранилища данных, то есть это те же самые переменные и константы, но с ограниченным доступом: они доступны только через экземпляр. Иначе говоря, вначале вы получаете доступ к экземпляру, а уже потом (через точку) — к его свойству.
Помимо свойств, у экземпляра могут быть определены методы. Методы, а с ними мы также неоднократно встречались, — это функции, которые определены внутри объектных типов. Класс Automobile мог бы иметь следующие методы: завестись, ускориться, посигналить:
bmw.startEngine()
bmw.accelerate()
bmw.beep()
Таким образом, создавая экземпляр, мы можем наполнять его свойства информацией и использовать его методы. И свойства, и методы определяются типом данных.
Способ разработки программ с использованием объектных типов называется объектно-ориентированным программированием. Этот стиль программирования позволяет достичь очень многого при разработке программ. Несмотря на то что вместо термина «объект» используется термин «экземпляр», аббревиатура ООП является устоявшейся в программировании, и в Swift она не трансформируется в ЭОП.
Пространства имен (namespaces) — это именованные фрагменты программ. Пространства имен имеют одно очень важное свойство — они скрывают свою внутреннюю реализацию и не позволяют получить доступ к объектам внутри пространства имен без доступа к самому пространству имен. Это замечательная черта, благодаря которой вы можете иметь объекты с одним и тем же именем в различных пространствах имен.
Мы уже неоднократно говорили об областях видимости переменных и функций. Пространства имен как раз и реализуют в приложении различные области видимости.
Простейшим примером ограничения области видимости может служить функция. Все переменные, объявленные в ней, вне функции — недоступны. Но при этом функция не является пространством имен, так как не позволяет получить доступ к объектам внутри себя извне.
К пространствам имен относятся перечисления, структуры и классы, о которых мы уже упоминали. Именно их изучением мы и займемся в этой главе. Также к пространствам имен относятся модули, но их рассмотрение не является темой данной книги, мы познакомимся с ними лишь поверхностно. Вообще, модули — это верхний уровень пространств имен. В простейшем варианте ваша программа — это модуль, а значит, это отдельное пространство имен, именем которого является название вашего приложения. Также модулями являются различные фреймворки. С одним из них, кстати, мы уже работали, когда выполняли операцию импорта: import Foundation.
Этот фреймворк называется Cocoa's Foundation Framework и содержит большое количество функциональных механизмов, позволяющих расширить возможности ваших программ.
Одни пространства имен могут включать другие: так, модуль UIKit, ориентированный на разработку iOS-приложений, в своем коде выполняет импорт модуля Cocoa's Foundation Framework.
Одной из главных проблем предыдущих версий Swift была нестандартизированность и неоднозначность написания имен функциональных элементов. Каждый разработчик сам определял, как он хочет называть создаваемые структуры, классы, перечисления, переменные и т.д. С одной стороны, это, конечно, хорошо, но если в своем проекте вы использовали библиотеки сторонних производителей, то синтаксис вашей программы мог превратиться в невнятное месиво. А если еще библиотеки были написаны на Objective-C, то разработку вообще хотелось забросить, настолько неудобным могло стать использование Swift.
Но вместе с выходом Swift 3 был разработан документ, определяющий правила именования любых элементов, будь то переменная, константа, функция, класс, перечисление, структура или что-то иное. Он получил название Swift API Design Guidelines.
Swift ADG — это своеобразная дорожная карта, собравшая правила, благодаря которым синтаксис языка стал четким, понятным и приятным. Когда вы достигнете определенного уровня в программировании и приступите к разработке собственных API-библиотек, то изучение приведенного в API Design Guidelines станет отличной базой для создания удобного и функционального продукта.
До разработки Apple Design Guidelines язык Swift был очень изменчив. Далее приведены некоторые наиболее важные правила.
• Комментарии необходимо писать для каждого объявляемого экземпляра в вашем коде. Комментарии должны быть максимально полными.
• Имена всех экземпляров должны быть ясными и краткими. Избегайте дублирования и избыточности. Избегайте пустых слов, не несущих смысловой нагрузки.
• Четкость и ясность именования экземпляров важнее краткости.
• Имена экземпляров должны исключать неоднозначность.
• Именуйте экземпляры в соответствии с их ролью и предназначением в программе.
• Именуйте экземпляры с использованием понятных и максимально простых фраз на английском языке.
• Названия типов данных указывайте в верхнем верблюжьем регистре (UpperCamelCase).
• Названия свойств, методов, переменных и констант указывайте в нижнем верблюжьем регистре (camelCase).
Используя этот небольшой набор правил, вы уже можете создавать приятные для чтения программы. Старайтесь! Включайте фантазию, и всё получится!