1. Темы лекции: ООП в JavaScript.
Тренер: Игорь Шкулипа, к.т.н.
JavaScript. Базовый курс
Занятие 4
2. http://www.slideshare.net/IgorShkulipa 2
ООП – это парадигма программирования, основанная на
представлении предметной области в виде взаимосвязанных абстрактных
объектов и их реализаций.
В ООП вводится понятие Класса – пользовательского типа
данных, объединяющего данные и методы их обработки.
Объектом называется экземпляр класса.
Объектно-ориентированное программирование
3. http://www.slideshare.net/IgorShkulipa 3
Члены-данные (поля) (data members) хранят всю необходимую
информацию об объекте, формируют его состояние, характеристики и
т.п.
Изменение состояния объекта или его характеристик связано с
изменением данных, которые в нем содержатся.
Метод объекта (methods) – программный код, выполненный в
виде функции, реагирующий на передачу объекту определенного
сообщения.
Вызов метода объекта может приводить к изменению его
состояния (значение членов-данных), а может и не приводить
Класс может содержать один или более методов, позволяющих
осуществлять манипуляцию данными объекта
Поля и методы класса
4. http://www.slideshare.net/IgorShkulipa 4
Свойство – составляющая часть объекта, доступ к которой
осуществляется как к члену объекта, но таковым не является (реализуют
принцип инкапсуляции для членов объекта).
В некоторых объектно-ориентированных языках
программирования (например, в C++) свойства, как элемент языка,
отсутствуют.
В этом случае в класс добавляют методы, посредством которых
осуществляется доступ к необходимым переменным класса.
Свойства
6. http://www.slideshare.net/IgorShkulipa 6
Объекты представляют неполную информацию о реальных
сущностях предметной области.
Абстракция позволяет оперировать с объектном на уровне,
адекватном решаемой задаче.
Высокоуровневые обращения к объекту могут обрабатываться с
помощью вызова функций и методов низкого уровня.
В основе реализации этого принципа лежит использование
абстрактных классов интерфейсов.
Абстракция данных
7. http://www.slideshare.net/IgorShkulipa 7
Инкапсуляция – объединение в одной оболочке данных и
методов их обработки, а так же способность объекта скрывать внутреннее
устройство своих полей и методов.
Согласно данному принципу, класс должен рассматриваться как
черный ящик.
Внешний пользователь не знает детали реализации объекта и
работает с ним только путем предоставленного объектом интерфейса (или
открытых методов доступа).
Следование данному принципу может уменьшить число связей
между классами и упростить их независимую реализацию, модификацию и
тестирование.
Инкапсуляция
8. http://www.slideshare.net/IgorShkulipa 8
Наследование позволяет описать новый класс на основе уже
существующего родительского (базового) класса.
Класс-потомок может добавить свои собственные свойства и
методы, а так же пользоваться методами и свойствами базового класса.
Наследование позволяет строить иерархии классов.
Наследование
9. http://www.slideshare.net/IgorShkulipa 9
Полиморфизмом называют явление, при котором классы-
потомки могут изменять реализацию метода класса-предка, сохраняя его
интерфейс.
Полиморфизм позволяет обрабатывать объекты классов-потомков
как однотипные объекты, не смотря на то, что реализация методов у них
может различаться.
Полиморфизм
10. http://www.slideshare.net/IgorShkulipa 10
Доступ к данным и методам класса извне может быть ограничен
Рекомендуется запрещать доступ к данным класса в обход его
методов
Для разделения прав доступа к полям класса используются
модификаторы доступа
public
private
protected
Доступ к данным и методам класса
11. http://www.slideshare.net/IgorShkulipa 11
public-методы и данные класса определяют его интерфейс доступ
к ним возможен из любой части кода.
Необходимо помещать в public-раздел класса только
необходимый набор методов, выполняющих высокоуровневые операции
над объектом класса
Открытые (public) поля и методы класса
12. http://www.slideshare.net/IgorShkulipa 12
private-данные и методы класса определяют его реализацию
Доступ к ним разрешен только из методов данного класса
Рекомендуется все данные класса делать закрытыми, их
обработку осуществлять внутри методов.
Закрытые методы класса обычно используются публичными
методами, решая внутренние задачи класса.
Закрытые (private) поля и методы класса
13. http://www.slideshare.net/IgorShkulipa 13
protected-данные и методы определяют интерфейс для
производных классов.
Доступ к ним разрешен внутри методов данного класса и всех его
потомков.
В защищенной зоне размещают методы, которые не должны быть
видны снаружи класса, но реализация которых может быть
переопределена или использована производными классами.
Защищенные (protected) поля и методы класса
14. http://www.slideshare.net/IgorShkulipa 14
Класс – тип данных.
Объект – переменная этого типа.
Для инициализации состояния объекта в момент его создания
существует специальный метод – конструктор. Конструктор имеет то же
имя, что и имя класса.
Конструктор вызывается в момент создания экземпляра класса
(объявление переменной класса или вызов оператора new).
Некоторые определения
15. http://www.slideshare.net/IgorShkulipa 15
• Нет классов, но можно их эмулировать.
• Есть наследование на прототипах - делегирующее прототипное
наследование
• Все можно менять во время работы
• Цепочку наследования можно менять
• Прототипы можно менять
• В классах так сделать нельзя
• Можно изменить прототипы базовых "классов“
• Любой объект имеет ссылку на прототип
• Делегирование
• Мы можем пользоваться функциями прототипа не имея
собственных
• Цепочка прототипов
• Каждый прототип - это тот же объект
• Который также может иметь прототип
• У прототипа прототипа также может быть прототип
Особенности ООП в JavaScript
16. http://www.slideshare.net/IgorShkulipa 16
Объекты JavaScript представляют собой наборы свойств и
методов. Можно сказать, что свойства объектов - это данные,
связанные с объектом, а методы - функции для обработки данных
объекта.
В общем случае, объект – это неупорядоченная коллекция пар
ключ-значение.
var o = {
firstName : ”Василий”,
lastName : ”Пупкин”,
age : 30,
};
Object
22. http://www.slideshare.net/IgorShkulipa 22
var o = {
name:"Ivan",
surname:"Ivanov"
};
o.middle = "Ivanovich";
o.gender = "Male";
delete o.gender;
delete o["middle"];
delete o["someprop1"];
delete o.someprop2;
for (var prop in o){
alert(o[prop]);
}
Удаление свойств
23. http://www.slideshare.net/IgorShkulipa 23
this возвращает ссылку на объект, являющийся текущим
контекстом вызова. Это позволяет обращаться к свойствам "текущего"
объекта: this.property.
Текущий объект не является жестко фиксированным и зависит от
контекста вызова функции. Он является, своего рода, скрытым
параметром.
this
24. http://www.slideshare.net/IgorShkulipa 24
var o = {
name:"Ivan",
surname:"Ivanov"
};
o.middle = "Ivanovich";
o.gender = "Male";
o.alertme1 = function() {
alert(this.name);
}
o.alertme2 = alerto;
o.alertme1();
o.alertme2();
function alerto() {
alert(this.name);
}
Методы
25. http://www.slideshare.net/IgorShkulipa 25
Объекты в JavaScript можно организовать в цепочки так, чтобы
свойство, не найденное в одном объекте, автоматически искалось бы в
другом.
Связующим звеном выступает специальное свойство __proto__.
Объект, на который указывает ссылка __proto__, называется
«прототипом».
Прототип объекта
27. http://www.slideshare.net/IgorShkulipa 27
var oproto = {
gender:"Male"
};
var o = Object.create (oproto, {
name:{
value:"Ivan",
writable:true,
configurable:true,
enumerable:true
},
surname:{
value:"Ivanov",
writable:true,
configurable:true,
enumerable:true
}
})
for (var prop in o){
alert(o[prop]);
}
Object.create()
28. http://www.slideshare.net/IgorShkulipa 28
Object.create(prototype, descriptors)
Дескрипторы свойств, присутствующие в объектах, бывают двух основных
типов: дескрипторы данных и дескрипторы доступа.
Дескриптор данных — это свойство, имеющее значение, которое может быть (а
может и не быть) записываемым.
Дескриптор доступа — это свойство, описываемое парой функций — геттером
и сеттером. Дескриптор может быть только чем-то одним из этих двух типов; он не
может быть одновременно обоими.
И дескриптор данных, и дескриптор доступа являются объектами. Они
обладают следующими обязательными ключами:
• configurable - равен true только в том случае, если тип этого дескриптора
свойства может быть изменён и если свойство может быть удалено из
содержащего его объекта. Значение по умолчанию установлено в false.
• enumerable - равен true только в том случае, если это свойство можно увидеть
через перечисление свойств содержащего его объекта. Значение по
умолчанию установлено в false.
Object.create()
29. http://www.slideshare.net/IgorShkulipa 29
Дескриптор данных также может содержать следующие дополнительные ключи:
• value - значение, ассоциированное со свойством. Может быть любым
допустимым значением JavaScript (числом, объектом, функцией и т.д.).
Значение по умолчанию установлено в undefined.
• writable - равен true только в том случае, если значение, ассоциированное
со свойством, может быть изменено с помощью оператора присваивания.
Значение по умолчанию установлено в false.
Дескриптор доступа также может содержать следующие дополнительные ключи:
• get - функция, используемая как геттер свойства, либо undefined, если
свойство не имеет геттера. Возвращаемое значение функции будет
использоваться как значение свойства. Значение по умолчанию установлено
в undefined.
• set - функция, используемая как сеттер свойства, либо undefined, если
свойство не имеет сеттера. Функция принимает единственным аргументом
новое значение, присваиваемое свойству. Значение по умолчанию
установлено в undefined.
Object.create()
30. http://www.slideshare.net/IgorShkulipa 30
var oproto = {
gender:"Male"
};
var o = Object.create (oproto, {
name:{
value:"Ivan",
writable:true,
configurable:true,
enumerable:true
},
surname:{
value:"Ivanov",
writable:true,
configurable:true,
enumerable:true
}
})
oproto.gender="Not Set";
for (var prop in o){
alert(o[prop]);
}
Прототип
33. http://www.slideshare.net/IgorShkulipa 33
Все объекты базовый набор методов, например метод toString,
которые находится, не в самом объекте, а в его прототипе obj.__proto__.
Объект Object.prototype — вершина иерархии, единственный, у
которого __proto__ равно null.
Поэтому говорят, что «все объекты наследуют от Object», а если
более точно, то от Object.prototype.
Object.prototype
34. http://www.slideshare.net/IgorShkulipa 34
Любая функция, кроме некоторых встроенных, может создать объект.
Для этого ее нужно вызвать через директиву new.
Такие функции еще называются конструкторами.
function FullName (name, surname, middle) {
this.name = name;
this.surname = surname;
this.middle = middle;
return this; // не обязательно
}
var fullName= new FullName (“Ivan“, “Ivanov”, “Ivanovich”);
Создание объектов с помощью функций
35. http://www.slideshare.net/IgorShkulipa 35
function FullName (name, surname, middle) {
this.name = name;
this.surname = surname;
this.middle = middle;
this.alertme = function (){
alert(this.name);
}
return this; // не обязательно
}
var o1= new
FullName("Ivan", "Ivanov", "Ivanovich");
var o2= new
FullName("Petr", "Petrov", "Petrovich");
o1.alertme();
o2.alertme();
Конструкторы
36. http://www.slideshare.net/IgorShkulipa 36
function FullName (name, surname, middle) {
this.name = name;
this.surname = surname;
this.middle = middle;
this.alertme = function (){
alert(this.name);
}
return {
name: "Sidor",
surname: "Sidorov",
middle: "Sidorovich",
alertme: function () {
alert(this.name);
}
};
}
var o1= new
FullName("Ivan", "Ivanov", "Ivanovich");
var o2= new
FullName("Petr", "Petrov", "Petrovich");
o1.alertme();
o2.alertme();
Конструкторы
37. http://www.slideshare.net/IgorShkulipa 37
Чтобы новым объектам автоматически ставить прототип,
конструктору ставится свойство prototype.
При создании объекта через new, в его прототип __proto__
записывается ссылка из prototype функции-конструктора.
Как правило, свойство prototype используется для
предоставления базового набора функциональных возможностей классу
объектов. Новые экземпляры объекта "наследуют" поведение прототипа,
присвоенного этому объекту.
F.prototype
38. http://www.slideshare.net/IgorShkulipa 38
var nameObj = { name: "", gender:""};
function Initials(name, middle){
this.name = name;
this.middle = middle;
}
function SurnName(name, surname){
this.name = name;
this.surname = surname;
}
Initials.prototype = nameObj;
SurnName.prototype = nameObj;
Initials.prototype.alertme = function () {
alert(this.name + " " +
this.surname + " " + this.gender);
}
var initials = new
Initials("Ivan", "Ivanovich");
var surnname = new
SurnName("Petr", "Petrov");
nameObj.gender = "male";
initials.alertme();
surnname.alertme();
nameObj.alertme();
Пример
40. http://www.slideshare.net/IgorShkulipa 40
В prototype по умолчанию всегда находится свойство
constructor, указывающее на функцию-конструктор. Но, если мы
рассчитываем использовать это свойство, то при замене prototype через
Object.create нужно его явно сохранить.
obj.prototype = Object.create(null);
obj.prototype.constructor = Object;
JavaScript никак не использует свойство constructor. То есть,
оно создаётся автоматически, а что с ним происходит дальше — это уже
наша забота. В стандарте прописано только его создание.
В частности, при перезаписи obj.prototype = { } свойства
constructor больше не будет.
Свойство constructor
41. http://www.slideshare.net/IgorShkulipa 41
var nameObj = { name: "", gender:""};
function Initials(name, middle){
this.name = name;
this.middle = middle;
}
function SurnName(name, surname){
this.name = name;
this.surname = surname;
}
SurnName.prototype = nameObj;
Initials.prototype.alertme = function () {
alert(this.name + " " + this.surname + " " +
this.gender);
}
var initials = new Initials("Ivan", "Ivanovich");
var surnname = new SurnName("Petr", "Petrov");
nameObj.gender = "male";
Пример
44. http://www.slideshare.net/IgorShkulipa 44
Все, что добавляется в this является public
function FullName (name, surname, middle) {
this.name = name;
this.surname = surname;
this.middle = middle;
this.alertme = function (){
alert(this.name);
}
return this;
}
var o1= new
FullName("Ivan", "Ivanov", "Ivanovich");
var o2= new
FullName("Petr", "Petrov", "Petrovich");
o1.alertme();
o2.alertme();
public
45. http://www.slideshare.net/IgorShkulipa 45
Все, что объявляется внутри конструктора, включая его параметры, является
private
function FullName (name, surname, middle) {
var fullName=name + " " + middle + " " + surname;
this.name = name;
this.surname = surname;
this.middle = middle;
this.alertme = function (){
alert(fullName);
}
return this;
}
var o1= new
FullName("Ivan", "Ivanov", "Ivanovich");
var o2= new
FullName("Petr", "Petrov", "Petrovich");
o1.alertme();
o2.alertme();
private
46. http://www.slideshare.net/IgorShkulipa 46
protected - это, по сути, public, отмеченный «_» в начале
идентификатора. И мы «договариваемся» эти свойства не трогать.
function FullName (name, surname, middle) {
var fullName=name + " " + middle + " " + surname;
this.name = name;
this.surname = surname;
this.middle = middle;
this._fullName = fullName;
this.alertme = function (){
alert(this._fullName);
}
return this;
}
var o1= new
FullName("Ivan", "Ivanov", "Ivanovich");
var o2= Object.create(new
FullName("Petr", "Petrov", "Petrovich"));
o1.alertme();
alert(o2._fullName);
protected
47. http://www.slideshare.net/IgorShkulipa 47
function Name () {
var name;
this.getName = function () {
return name;
}
this.setName = function (nm) {
nm = nm || null;
if (nm && (nm.length > 0))
name=nm;
else name="";
}
}
var n1=new Name();
var n2=new Name();
var n3=new Name();
n1.setName();
n2.setName(2);
n3.setName("3");
alert(n1.getName());
alert(n2.getName());
alert(n3.getName());
Инкапсуляция
48. http://www.slideshare.net/IgorShkulipa 48
var n0 = Object.create(null,{
name:{
configurable: true,
enumerable: true,
get: function () {
return name + ", hello GET!";
},
set: function (nm) {
nm = nm || null;
if (nm && (nm.length > 0))
name=nm;
else name="Default";
}
}
});
n0.name="Ivan";
alert(n0.name);
n0.name="";
alert(n0.name);
Инкапсуляция 2
49. http://www.slideshare.net/IgorShkulipa 49
function Name () {
var name;
this.getName = function () {
return name;
}
this.setName = function (nm) {
nm = nm || null;
if (nm && (nm.length > 0))
name=nm;
else name="";
}
}
function FullName () {
Name.call(this);
var surname = "S";
var middle = "M";
this.getName = function (){
return name + " " +
middle + " " + surname;
}
}
Наследование
50. http://www.slideshare.net/IgorShkulipa 50
function Name () {
this._name="";
this.getName = function () {
return this._name;
}
this.setName = function (nm) {
nm = nm || null;
if (nm && (nm.length > 0))
this._name=nm;
else this._name="";
}
}
function FullName () {
Name.call(this);
var surname = "S";
var middle = "M";
this.getName = function (){
return this._name + " " +
middle + " " + surname;
} }
var n1= new FullName();
var n2= new FullName();
var n3= new FullName();
n1.setName();
n2.setName(2);
n3.setName("3");
alert(n1.getName());
alert(n2.getName());
alert(n3.getName());
Наследование
51. http://www.slideshare.net/IgorShkulipa 51
Сериализация (в программировании) — процесс перевода
какой-либо структуры данных в последовательность битов. Обратной к
операции сериализации является операция десериализации
(структуризации) — восстановление начального состояния структуры
данных из битовой последовательности.
Почти все языки программирования имеют библиотеки для
преобразования объектов в формат JSON.
Основные методы для работы с JSON в JavaScript — это:
• JSON.parse — читает объекты из строки в формате JSON.
• JSON.stringify — превращает объекты в строку в формате JSON,
используется, когда нужно из JavaScript передать данные по сети.
Сериализация
52. http://www.slideshare.net/IgorShkulipa 52
JSON (JavaScript Object Notation) — текстовый формат обмена данными,
основанный на JavaScript.
JSON строится на двух структурах:
• Коллекция пар ключ/значение. В разных языках, эта концепция
реализована как объект, запись, структура, словарь, хэш, именованный
список или ассоциативный массив.
• Упорядоченный список значений. В большинстве языков это реализовано
как массив, вектор, список или последовательность.
В JSON используются их следующие формы:
• Объект — это неупорядоченное множество пар имя/значение,
заключённое в фигурные скобки { }. Между именем и значением стоит
символ ": ", а пары имя/значение разделяются запятыми.
• Массив (одномерный) — это множество значений, имеющих порядковые
номера (индексы). Массив заключается в квадратные скобки [ ]. Значения
отделяются запятыми.
• Значение может быть строкой в двойных кавычках, числом, значением
true или false, объектом, массивом, или значением null. Эти структуры
могут быть вложены друг в друга.
• Строка — это упорядоченное множество из нуля или более символов
юникода, заключенное в двойные кавычки, с использованием escape-
последовательностей начинающихся с обратной косой черты (backslash).
Символы представляются простой строкой.
• Имя — это строка.
JSON
54. http://www.slideshare.net/IgorShkulipa 54
var initialsString= JSON.stringify(initials);
var surnnameString= JSON.stringify(surnname);
alert(initialsString);
alert(surnnameString);
var ini= JSON.parse(initialsString);
var sur= JSON.parse(surnnameString);
alert(ini.name);
alert(sur.name);
Сериализация
55. http://www.slideshare.net/IgorShkulipa 55
Ошибки в скриптах делятся на два типа:
• Синтаксические ошибки — когда нарушена структура кода.
Обычно это ошибки программиста. Их также называют «ошибки
времени компиляции», поскольку они происходят на этапе
разбора кода.
• Семантические ошибки, также называемые «ошибки времени
выполнения» — возникают, когда браузер смог прочитать скрипт
и уже выполняет код, но вдруг натыкается на проблему.
Обработка исключений
56. http://www.slideshare.net/IgorShkulipa 56
• Выполняется код внутри блока try.
• Если в нём возникнет ошибка, то выполнение try прерывается, и
управление прыгает в начало блока catch.
try {
alert("Start try");
a;
alert("End of try");
} catch (error) {
alert("Error catched!");
}
Конструкция try-catch. С ошибкой
58. http://www.slideshare.net/IgorShkulipa 58
У блока catch есть аргумент, в примере выше он обозначен error.
Это — объект ошибки или, как ещё говорят, объект исключения (exception
object).
Он содержит информацию о том, что произошло, и может быть
разным, в зависимости от ошибки.
Как правило, error — объект встроенного типа Error и производных от
него.
Есть несколько свойств, которые присутствуют в объекте ошибки:
• name - тип ошибки. Например, при обращении к несуществующей
переменной равен "ReferenceError".
• message - текстовое сообщение о деталях ошибки.
• stack - везде, кроме IE<9, есть также свойство stack,
указывающее, где в точности произошла ошибка.
Объект ошибки
61. http://www.slideshare.net/IgorShkulipa 61
try {
alert("Start try");
var a = 1;
var b = a();
alert("End of try");
} catch (error) {
alert(error);
} finally {
alert("Finally");
}
Блок finally позволяет избежать дублирования
кода в try-catch.
Секция finally
62. http://www.slideshare.net/IgorShkulipa 62
Блок finally срабатывает при любом выходе из try-catch, в том числе и
return. Это гарантирует освобождение ресурсов в любом случае.
function f() {
try {
alert("Start try");
return 1;
} catch (error) {
alert(error);
} finally {
alert("Finally");
}
}
f();
finally и return
63. http://www.slideshare.net/IgorShkulipa 63
throw <объект ошибки>
Инициирует ошибку, которую можно
поймать в catch. Объектом ошибки
может быть что угодно, например
число.
try {
alert("Start try");
throw 1;
} catch (error) {
alert(error);
} finally {
alert("Finally");
}
Генерация ошибок
64. http://www.slideshare.net/IgorShkulipa 64
В случае вложенных вызовов — не важно, где было исключение,
оно будет поймано ближайшим внешним try-catch.
function f() {
while (true) {
throw 1;
}
}
try {
alert("Start try");
f();
} catch (error) {
alert(error);
} finally {
alert("Finally");
}
Всплывание ошибок
66. http://www.slideshare.net/IgorShkulipa 66
SOLID – это акроним названий пяти основных принципов
проектирования классов, сформулированных Робертом Мартином:
• Single responsibility (принцип одной ответственности),
• Open for extension and closed for modification (принцип
открытости/закрытости, или открытость для расширения и
закрытость для модификации),
• Liskov substitution (принцип подстановки Лисков),
• Interface segregation (принцип разделения интерфейса),
• Dependency inversion (принцип инверсии зависимостей).
SOLID. Принципы проектирования
67. http://www.slideshare.net/IgorShkulipa 67
Принцип единственной ответственности (Single Responsibility
Principle) часто определяют так: у объекта должна быть только одна
причина для изменения; чем больше файл или класс, тем труднее
достичь этой цели.
Этот принцип говорит о том, что по-хорошему каждый класс
должен решать только одну задачу. Это совсем не значит, что в классе
должен быть всего один метод. Это означает, что методы класса должны
быть связаны одной общей целью.
Single Responsibility
68. http://www.slideshare.net/IgorShkulipa 68
Single Responsibility
Плохой пример Неплохой пример
function Persone(name, surname, middle) {
this.name=name;
this.surname=surname;
this.middle=middle;
return this;
}
Persone.prototype.LoadFromDatabase =
function () {}
Persone.prototype.SaveToDatabase =
function () {}
Persone.prototype.PrintToPrinter =
function () {}
function Persone(name, surname, middle) {
this.name=name;
this.surname=surname;
this.middle=middle;
return this;
}
function PersoneDatabase() {
return this;
}
PersoneDatabase.prototype.LoadFromDatabase =
function () { return new Persone(...);}
PersoneDatabase.prototype.SaveToDatabase =
function (p) { }
function PersonePrinter() {
return this;
}
PersonePrinter.prototype.PrintToPrinter =
function (p) { }
69. http://www.slideshare.net/IgorShkulipa 69
Объекты проектирования (классы, функции, модули и т.д.)
должны быть открыты для расширения, но закрыты для модификации.
Этот принцип говорит о том, что классы нужно проектировать
так, чтобы впоследствии иметь возможность изменять поведение класса,
не изменяя его код.
Open for Extension and Closed for Modification
70. http://www.slideshare.net/IgorShkulipa 70
Open for Extension and Closed for Modification
Плохой пример Неплохой пример
function PersonePrinter () {
}
PersonePrinter.prototype.PrintToPrinter =
function (p) { }
function PersonePrinter () {
}
PersonePrinter.prototype.PrintToPrinter =
function (p) { }
PersonePrinter.prototype.PrintToPrinterShortForm =
function (p) { }
PersonePrinter.prototype.PrintToPrinterDetailedForm =
function (p) { }
function PersonePrinter () {
}
PersonePrinter.prototype.PrintToPrinter =
function (persone, printForm) { }
var PrintForm = { formats : [] }
function PrintFormGeneral () { }
PrintFormGeneral.prototype = PrintForm;
function PrintFormShort () { }
PrintFormShort.prototype = PrintForm;
function PrintFormDetailed () { }
PrintFormDetailed.prototype = PrintForm;
72. http://www.slideshare.net/IgorShkulipa 72
Liskov Substitution
Плохой пример Неплохой пример
function PersonePrinter () {
}
PersonePrinter.prototype.PrintToPrinter =
function (persone, printForm) {
//...
if (printForm instanceof PrintFormGeneral)
{ }
//...
if (printForm instanceof PrintFormShort)
{ }
}
function PersonePrinter () {
}
PersonePrinter.prototype.PrintToPrinter =
function (persone, printForm) {
//...
printForm.formatReport(persone);
//...
}
73. http://www.slideshare.net/IgorShkulipa 73
Interface Segregation
Плохой пример Неплохой пример
function Employee () {
this.UseComputer = function () { };
this.Develop = function () { };
this.Test = function () { };
}
function SoftDeveloper (){
Employee.call(this);
this.Develop = function() { }
this.Test = function() {/* How ? */ }
return this;
}
function SoftTester (){
Employee.call(this);
this.Develop = function() { /* How ? */ }
this.Test = function() { }
return this;
}
function Employee () {
this.UseComputer = function () { };
}
function SoftDeveloper (){
Employee.call(this);
this.Develop = function() { }
return this;
}
function SoftTester (){
Employee.call(this);
this.Test = function() { }
return this;
}
74. http://www.slideshare.net/IgorShkulipa 74
• Модули верхних уровней не должны зависеть от модулей
нижних уровней.
• Оба типа модулей должны зависеть от абстракций.
• Абстракции не должны зависеть от реализаций.
• Реализации должны зависеть от абстракций.
Dependency Inversion
75. http://www.slideshare.net/IgorShkulipa 75
Dependency Inversion
Плохой пример Неплохой пример
function SoftDeveloper () {
this.Develop = function () { }
}
function Manager () {
var softDeveloper = new SoftDeveloper();
this.Manage = function() {
softDeveloper.Develop();
}
}
function SoftDeveloper () {
this.Develop = function () { }
}
function Manager (softDeveloper) {
var sd = softDeveloper;
this.Manage = function() {
sd.Develop();
}
}
76. http://www.slideshare.net/IgorShkulipa 76
Паттерн описывает задачу, которая снова и снова возникает в работе, а так
же принцип ее решения, причем таким образом, что это решение можно потом
использовать много раз, ничего не изобретая заново.
В общем случае паттерн состоит из четырех основных элементов:
• Имя. Присваивание паттернам имен позволяет проектировать на более высоком
уровне абстракции. С помощью имен паттернов можно вести общение с коллегами.
Назначение паттернам имен упрощает общение в профессиональной среде.
• Задача - это описание того, когда следует применять паттерн. Необходимо
сформулировать задачу и ее контекст. Может описываться конкретная проблема
проектирования, например способ представления алгоритмов в виде объектов. Так
же задача может включать перечень условий, при выполнении которых имеет
смысл применять данный паттерн.
• Решение представляет собой описание элементов дизайна, отношений между
ними, функций каждого элемента. Конкретный дизайн или реализация не имеются
ввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.
• Результаты - это следствия применения паттерна и разного рода компромиссы.
Хотя при описании проектных решений о последствиях часто не упоминают, знать
о них необходимо, чтобы можно было выбрать между различными вариантами и
оценить преимущества и недостатки данного паттерна.
Паттерны (шаблоны проектирования)
77. http://www.slideshare.net/IgorShkulipa 77
Паттерны проектирования программных систем делятся на
следующие категории:
• Архитектурные паттерны. Описывают структурную схему
программной системы в целом. В данной схеме указываются отдельные
функциональные составляющие системы, называемые подсистемами, а
также взаимоотношения между ними.
• Паттерны проектирования. описывают схемы детализации
программных подсистем и отношений между ними, при этом они не
влияют на структуру программной системы в целом и сохраняют
независимость от реализации языка программирования.
• Идиомы - низкоуровневые паттерны, имеют дело с вопросами
реализации какой-либо проблемы с учетом особенностей данного языка
программирования.
Классификация паттернов
78. http://www.slideshare.net/IgorShkulipa 78
Паттерны проектирования делятся на следующие категории:
• Порождающие - шаблоны проектирования, которые абстрагируют
процесс создания объектов. Они позволяют сделать систему независимой
от способа создания, композиции и представления объектов.
• Структурные - шаблоны проектирования, в которых рассматривается
вопрос о том, как из классов и объектов образуются более крупные
структуры.
• Поведенческие - шаблоны проектирования, определяющие
алгоритмы и способы реализации взаимодействия различных объектов и
классов.
Паттерны проектирования (GoF)
79. http://www.slideshare.net/IgorShkulipa 79
• Singleton (Одиночка) - контролирует создание единственного
экземпляра некоторого класса и предоставляет доступ к нему.
• Factory Method (Фабричный метод) - В его классическом варианте
вводится полиморфный класс Factory, в котором определяется
интерфейс фабричного метода, а ответственность за создание
объектов конкретных классов переносится на производные от Factory
классы, в которых этот метод переопределяется.
• Abstract Factory (Абстрактная фабрика) - использует несколько
фабричных методов и предназначен для создания целого семейства
или группы взаимосвязанных объектов.
• Builder (Строитель) - определяет процесс поэтапного конструирования
сложного объекта, в результате которого могут получаться разные
представления этого объекта.
• Prototype (Прототип) - создает новые объекты с помощью прототипов.
Прототип - некоторый объект, умеющий создавать по запросу копию
самого себя.
• Object Pool (Пул объектов) - используется в случае, когда создание
объекта требует больших затрат или может быть создано только
ограниченное количество объектов некоторого класса.
Порождающие паттерны
80. http://www.slideshare.net/IgorShkulipa 80
• Adapter представляет собой программную обертку над уже
существующими классами и предназначен для преобразования их
интерфейсов к виду, пригодному для последующего использования в
новом программном проекте.
• Bridge отделяет абстракцию от реализации так, что то и другое
можно изменять независимо.
• Composite группирует схожие объекты в древовидные структуры.
Рассматривает единообразно простые и сложные объекты.
• Decorator используется для расширения функциональности объектов.
Являясь гибкой альтернативой порождению классов, паттерн
Decorator динамически добавляет объекту новые обязанности.
• Facade предоставляет высокоуровневый унифицированный
интерфейс к набору интерфейсов некоторой подсистемы, что
облегчает ее использование.
• Flyweight использует разделение для эффективной поддержки
множества объектов.
• Proxy замещает другой объект для контроля доступа к нему.
Структурные шаблоны проектирования
81. http://www.slideshare.net/IgorShkulipa 81
• Паттерн Chain of Responsibility позволяет обработать запрос
нескольким объектам-получателям. Получатели связываются в
цепочку, и запрос передается по цепочке, пока не будет обработан
каким-то объектом. Паттерн Chain of Responsibility позволяет также
избежать жесткой зависимости между отправителем запроса и его
получателями.
• Паттерн Command преобразовывает запрос на выполнение действия в
отдельный объект-команду. Это придает системе гибкость: позволяет
осуществлять динамическую замену команд, использовать сложные
составные команды, осуществлять отмену операций.
• Паттерн Iterator предоставляет механизм обхода элементов составных
объектов (коллекций) не раскрывая их внутреннего представления.
• Паттерн Interpreter предназначен для решения повторяющихся
задач, которые можно описать некоторым языком. Для этого паттерн
Interpreter описывает решаемую задачу в виде предложений этого
языка, а затем интерпретирует их.
• Паттерн Mediator инкапсулирует взаимодействие совокупности
объектов в отдельный объект-посредник. Уменьшает степень
связанности взаимодействующих объектов - им не нужно хранить
ссылки друг на друга.
Шаблоны поведения
82. http://www.slideshare.net/IgorShkulipa 82
• Паттерн Memento получает и сохраняет за пределами объекта его
внутреннее состояние так, чтобы позже можно было восстановить объект в
таком же состоянии.
• Паттерн Observer определяет зависимость "один-ко-многим" между
объектами так, что при изменении состояния одного объекта все
зависящие от него объекты уведомляются и обновляются автоматически.
• Паттерн State позволяет объекту изменять свое поведение в зависимости
от внутреннего состояния. Создается впечатление, что объект изменил
свой класс. Паттерн State является объектно-ориентированной
реализацией конечного автомата.
• Если поведение системы настраивается согласно одному из некоторого
множества алгоритму, то применение паттерна Strategy переносит
семейство алгоритмов в отдельную иерархию классов, что позволяет
заменять один алгоритм другим в ходе выполнения программы. Кроме
того, такую систему проще расширять и поддерживать.
• Паттерн Template Method определяет основу алгоритма и позволяет
подклассам изменить некоторые шаги этого алгоритма без изменения его
общей структуры.
• Паттерн Visitor определяет операцию, выполняемую на каждом элементе
из некоторой структуры без изменения классов этих объектов.
Шаблоны поведения
83. http://www.slideshare.net/IgorShkulipa 83
var Singleton = (function () {
var instance;
function createInstance() {
return {
name: "Ivan",
surname: "Ivanov",
alertme: function () {
alert(this.name+" "+this.surname);}
}
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
var instance1 = Singleton.getInstance();
instance1.name= "Petr";
var instance2 = Singleton.getInstance();
alert(instance1 === instance2);
instance1.alertme();
instance2.alertme();
Шаблон проектирования Singleton
84. http://www.slideshare.net/IgorShkulipa 84
Применяется, когда нужен только один экземпляр класса.
Например для хранения глобальной конфигурации системы, для
ведения логов, связи с базой данных и т.д.
Основное преимущество перед глобальными переменными в
том, что экземпляр класса создается не при инициализации
программы, а по первому требованию.
Применение Singleton