OOP Flashcards
Абстракция (ООП)
Abstraction
Мы абстрогируемся от незначительных характеристик и подробностей, используем только необходимое.
Абстракция – это принцип, который гласит, что класс должен представлять лишь такую информацию, которая соответствует контексту задачи, при этом с достаточной точностью для решаемой задачи. Чем меньше характеристик содержит объект, тем лучше абстракция. Проще говоря, мы представляем вовне лишь те свойства и методы, которые собираемся использовать. Если же что-то не нужно, то оно не раскрывается. Этот принцип тесно связан с инкапсуляцией, поскольку мы можем использовать публичные и закрытые свойства/методы, определяя, что раскрывать, а что нет.
В качестве примера абстракции можно рассмотреть класс Timer - он содержит только минимально необходимые для своей работы публичные методы (старт, стоп), при этом несущественные детали их реализации скрыты внутри и не имеют значения для его использования.
Видеоигры: если говорить о персонаже игры нам не важно сколько у него полигонов, какая у него развертка 3d-модели, как именно прописано его движение в программе, нам важны - атака, скорость, характеристики.
Инкапсуляция (ООП)
encapsulation
Класс как капсула, мы решаем какие свойства и методы будут видны извне.
Под инкапсуляцией подразумевается сокрытие полей внутри объекта с целью защиты данных от внешнего, бесконтрольного изменения со стороны других объектов. Объект «решает», какую информацию он будет раскрывать для внешнего мира, а какую нет. Доступ к данным (полям) предоставляется посредством публичных и закрытых свойств и методов. В JS все свойства объектов и методы по умолчанию являются публичными. Это защитный барьер позволяет хранить информацию в безопасности внутри объекта. Инкапсуляция полезна в случаях, когда нам требуются определённые свойства или методы исключительно для внутренних процессов объекта, и мы не хотим раскрывать их вовне. Наличие закрытых свойств/методов гарантирует, что мы «случайно» не раскроем эту информацию.
Видеоигры: к примеру, мы хотим добавить врагам свойство evilPlan, которое будет использоваться для метода comeUpWithAnEvilPlan. Но мы не хотим, чтобы это свойство было доступно вне самого объекта. Тут на помощь приходит инкапсуляция. Мы можем сделать evilPlan приватным и использовать его в методе.
Инкапсуляцию часто связывают с сокрытием данных (data hiding) от прямого внешнего обращения (обычно с помощью ключевых слов private, protected, public)
Для сокрытия внутреннего интерфейса мы используем защищённые или приватные свойства:
public — общедоступные
_protected —доступные только для потомков. Программисты должны обращаться к полю, начинающемуся с _, только из его класса и классов, унаследованных от него. Это хорошо известное соглашение, не поддерживаемое на уровне языка.
#private — доступные только внутри класса. JavaScript гарантирует, что мы можем получить доступ к таким полям только внутри класса.
Классы и методы класса (ООП)
Дальше мы приступаем к чертежам конкретных моделей, по которым уже можно построить реальные самолеты. Это классы. Да, класс это именно чертеж и только чертеж.
У конкретных классов должны определены все параметры унифицированного самолета и возможно добавлены новые. Мы должны определить как наш будущий самолет
будет садиться, взлетать, как он будет летать. Это методы класса. Также у него должны быть свойства: модель, год выпуска и так далее.
Композиция (ООП)
Object Composition
Части объекта составляют единую композицию. Композиция — это включение объектом-контейнером объекта-содержимого и управление его поведением; последний не может существовать вне первого. Композиция размещается внутри конструктора. При создании класса-контейнера он будет включать вызовы других классов, и при создании объекта этого класса, будут созданы объекты включенных в него вызовов классов.
Если сущность А является сущностью Б, то скорее всего здесь подойдет наследование. Если же сущность А является частью сущности Б, то наш выбор - композиция. Сущность А может быть частью сущности Б, но также может принадлежать и другим сущностям? В этом случае это будет агрегация. Наследование предполагает принадлежность к какой-то общности (похожесть), а композиция - формирование целого из частей.
Видеоигры: мы создаем главного героя компьютерной игры. У него будет свой голос, своя моделька и так далее. Они не существуют отдельно от него и будут полностью управляться классом герой.
Пример: двигатель не существует отдельно от автомобиля. Он создается при создании автомобиля и полностью управляется автомобилем. В типичном примере, экземпляр двигателя будет создаваться в конструкторе автомобиля. А вот ароматизатор салона - это агрегация (он может быть дома, в машине или еще где-то)
Наследование (ООП)
inheritance
Наследует описание класса на основе другого
Наследование - концепция объектно-ориентированного программирования, классы образуют иерархию наследования. Наследование — это механизм, позволяющий описать новый класс на основе уже существующего с добавлением новых свойств и методов. Новый класс называется потомком (дочерним, производным), а класс, на основе которого происходит создание нового, называется родителем (предком, базовым).
Сущность А является сущностью Б? Если да, то скорее всего, тут подойдет наследование. Если же сущность А является частью сущности Б, то наш выбор — композиция.
Пример с самолетами: Если мы создали модель пассажирского самолета на 120 мест, а потом чуть-чуть доработали увеличив количество мест до 130 (за счет сокращения бизнес класса), нам не потребуется создавать новый чертеж, достаточно лишь указать изменения. Тут же становится легко понятно, почему если поменяется что-то в чертеже модели самолета на 120 мест, так же измениться самолет на 130 мест, так мы не делаем копию чертежей, мы только описываем, что изменилось в проекте. Это наследование.
Видеоигры: мы прописали классы персонажей и все они будут врагами основного героя. И являясь врагами, они все будут иметь свойство power и метод attack. Их можно было бы добавить во все классы, но тогда код будет повторяться, чего желательно избегать (согласно принципу DRY - Don’t repeat yourself). Более удачным решением будет объявить родительский класс Enemy, который затем будет расширен всеми видами врагов. В дочернем классе с помощью ключевого слова extends мы объявляем родительский класс, от которого хотим реализовать наследование. Затем в конструкторе нам нужно объявить параметр power и с помощью функции super указать, что это свойство объявлено в родительском классе.
class Employee extends Person {...}
Чтобы унаследовать от класса:class Child extends Parent {// Код дочернего класса}
При этом Child.prototype.\_\_proto\_\_
будет равен Parent.prototype
, так что методы будут унаследованы.
При переопределении конструктора:
class Child extends Parent {
constructor() {
super(); // Обязателен вызов конструктора родителя
// Код дочернего конструктора
}
}
Обязателен вызов конструктора родителя super()
в конструкторе Child
до обращения к this
.
При переопределении другого метода:
class Child extends Parent {
method() {
super.method(); // Вызов метода родителя
// Код дочернего метода
}
}
Мы можем использовать super.method()
в методе Child
для обращения к методу родителя Parent
.
Внутренние детали:
Методы запоминают свой объект во внутреннем свойстве [[HomeObject]]
. Благодаря этому работает super
, он в его прототипе ищет родительские методы. Поэтому копирование метода, использующего super
, между разными объектами небезопасно.
Класс может наследовать только от одного родителя. Расширять несколько классов нельзя, хотя для этого есть свои хитрости. Вы можете безгранично увеличивать цепочку наследования, устанавливая родительский, «дедовский», «прадедовский» и так далее классы.
При наследовании все родительские методы и свойства переходят к потомку. Здесь мы не можем выбирать, что именно наследовать. Дочерние классы могут переопределять родительские свойства и методы.
Если дочерний класс наследует какие-либо свойства от родительского, то он сначала должен присвоить эти свойства через вызов функции super()
и лишь затем устанавливать свои.
У функций-стрелок нет своего this
и super
, поэтому они «прозрачно» встраиваются во внешний контекст.
Объектно-ориентированное программирование
Object-oriented programming
Объектно-ориентированное программирование — методология программирования, основанная на представлении программы в виде совокупности взаимодействующих объектов, каждый из которых является экземпляром определённого класса, а классы образуют иерархию наследования.
Базовые принципы ООП:
- Наследование
- Инкапсуляция
- Полиморфизм
- Иногда к ним добавляют Абстракцию
Перегрузка (ООП)
Operator overloading
Перегрузка - один из способов реализации полиморфизма, это определение в одной и той же области видимости нескольких методов с одинаковым именем, но различающихся количеством или типами параметров.
Если в классе-потомке переопределить уже существующий в классе-родителе метод, то сработает перегрузка. Это позволяет не дополнять поведение родительского класса, а модифицировать. В момент вызова метода или обращения к полю объекта, поиск атрибута происходит от потомка к самому корню — родителю. То есть, если у автобота вызвать метод fire(), сначала поиск метода производится в классе-потомке — Autobot, а поскольку его там нет, поиск поднимается на ступень выше — в класс Transformer, где и будет обнаружен и вызван.
Поле класса (ООП)
Поле класса в ООП мире называется переменная, связанная с классом или объектом. Все данные объекта хранятся в его полях. Доступ к полям осуществляется по их имени. У полей есть альтернативные названия:
- атрибут класса
- переменная-член класса
Поля бывают собственные (обычные) и общие для всех объектов (экземпляров (instance’ов)) класса (статические).
По области видимости поля бывают:
public — общедоступные
_protected —доступные только для потомков
#private — доступные только внутри класса
Полиморфизм (ООП)
Polymorphism
Много форм.
Полиморфизм - у каждого класса есть свой метод, который (при вызове) выполняется корректно для любого объекта. Идея заключается в способности вызывать один и тот же метод для разных объектов, и при этом каждый объект реагирует по-своему. Чтобы это произошло полиморфизм использует наследование. Данный принцип позволяет программистам использовать одни и те же термины для описания различного поведения, зависящего от контекста. Одной из форм полиморфизма является переопределение метода, когда различные формы поведения определяются объектом из которого данный метод был вызван. Другой формой полиморфизма является перегрузка метода, когда его поведение определяется набором передаваемых в метод аргументов.
Виды полиморфизма:
ad-hoc («специальный полиморфизм») - поддерживается во многих языках посредством перегрузки функций и методов и приведения типов. Работают с конечным набором конкретных типов, не связанных между собой, где для каждого типа аргументов реализуется свой способ вычислений.
Перегрузка (overloading) — синтаксический механизм, позволяющий объявлять функции с одним и тем же именем, но с разными типами аргументов и их количеством (арностью). Говоря другими словами, у функции может быть несколько сигнатур.
в слабо типизированных используется приведение типов (coercion): 1 + 1; // 2 и ‘cat’ + ‘dog’; // catdog
универсальный (universal). Универсально полиморфные функции работают на неограниченном количестве типов, причем функция будет выполняться для любого типа аргументов.
Параметрический (parametric) - свойство семантики системы типов, позволяющее обрабатывать значения разных типов идентичным образом, то есть исполнять физически один и тот же код для данных разных типов
полиморфизм включений (inclusion) - в этом виде полиморфизма функции или операторы могут содержать один или множество аргументов, типы которых имеют подтипы.
Видеоигры: К примеру, у нас есть единый класс Враги. Он имеет метод angryLaughAndFinalPhrase. Мы можем переопределить потомками этого класса этот метод, чтобы каждый злодей смеялся по своему и говорил герою о своих личных злобных планах.
Пример с самолетами: Если мы сделали унифицированную (приведенную к единому виду) модель самолета с определенным размахом крыльев, мы можем быть уверены, что любой из наших самолетов (военных, гражданских или грузовых) сможет сесть на ВВП, предназначенную для данного типа самолета (не зависимо от того, что как они будут садиться).
Пример с транспортом и move(). В абстрактном классе Transport находится абстрактный метод move. Абстрактный метод move не реализуется для класса, в котором описан, однако должен быть реализован для его неабстрактных потомков.
class Car extends Transport {
constructor(type: string, model: string) {
super(type, model)
}
//
public move(): void {
console.log('Moving on the road');
}
}
//
class Plane extends Transport {
constructor(type: string, model: string) {
super(type, model)
}
//
public move() {
console.log('Flying in the sky');
}
}
//
class Ship extends Transport {
constructor(type: string, model: string) {
super(type, model)
}
//
public move() {
console.log('Moving on the water');
}
}
Реализация (ООП)
realization
Реализация – это семантическая связь между двумя классификаторами, один из которых описывает контракт, а другой обязуется его исполнять. Этот тип отношений базируется на интерфейсах. То есть создаются интерфейсы, которые основной класс должен реализовать.
Статические методы и переменные класса (ООП)
У каждой модели самолета есть общие параметры, например, процент аварийности. Каждое происшествие с любым самолетом этой модели его может изменить. Это статические методы и переменные класса.
абстрактный класс (ООП)
Abstract type
Абстрактный класс базовый класс, который не предполагает создания экземпляров. Абстрактные классы реализуют на практике один из принципов ООП — полиморфизм. От обычных классов они отличаются тем, что нельзя создать объект такого класса. Он нужен для того, чтобы от него могли наследоваться потомки — обычные классы, объекты которых уже можно создавать. Абстрактный класс — это «заготовка» класса: реализовано большинство методов (включая внутренние), кроме нескольких. Эти несколько нереализованных методов вполне могут быть внутренними методами класса, они лишь уточняют детали имплементации. Абстрактный класс — средство для повторного использования кода, средство, чтобы указать, какой метод обязан быть перекрыт для завершения написания класса.
Пример с самолетами: Нам заказали грузовой, пассажирский и военный самолет. Мы чертим некоторый общий чертеж для всех моделей. По этому чертежу еще нельзя построить реальный самолет, но он уже содержит общие детали реализации - это абстрактный класс. > Anastasia: виртуальные методы и члены класса (ООП)
агрегация (ООП)
Object aggregation
Агрегация — включение объектом-контейнером ссылки на объект-содержимое; при уничтожении первого последний продолжает существование.
Сущность А является сущностью Б? Если да, то скорее всего, тут подойдет наследование.
Если же сущность А является частью сущности Б, то наш выбор — композиция.
Сущность А являются частью сущности Б, но может принадлежать и другим и при удалении сущности А продолжит существование? Это агрегация.
Наследование предполагает принадлежность к какой-то общности (похожесть), а композиция — формирование целого из частей.
Видеоигры: во многих играх есть торговцы, мы можем создать такую сущность как часть локации Деревня или как часть локации Город, т.е. торговец существует вне локации деревня и передается туда извне через параметры конструктора.
Пример: у машины колеса и двигатель - это композиция, а вот ароматизатор салона - это агрегация (она может быть дома, в машине или еще где-то), т.е. он существует вне автомобиля и передается туда извне через параметры конструктора.
ассоциация (ООП)
Традиционно в полях объекта могут храниться не только обычные переменные стандартных типов, но и другие объекты. А эти объекты могут в свою очередь хранить какие-то другие объекты и так далее, образуя дерево (иногда граф) объектов. Это отношение называется ассоциацией. Ассоциация это такой тип при котором объекты будут ссылаться друг на друга. При этом они остаются полностью независимыми друг от друга.
Пример с самолетами: Если мы разрабатываем трап, подходящий под этот тип самолета (и, возможно, другие подробные самолеты), пилот самолета при приземлении просит подать именно этот трап. Это будет ассоциация.
делегация (ООП)
Delegation
Делегация — перепоручение задачи от внешнего объекта внутреннему;