diff --git a/README.md b/README.md index fc64f0b..6827786 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,376 @@ -# Как делать +# Доп информация + +## Как делать дз 0. Сделать форк этого репозитория в свой аккаунт 1. Перед выполнением ДЗ сделайте пул мастера этого репозитория себе в форк (чтобы иметь актуальный код); 2. Обновить зависимости `yarn` или `npm i`; 4. Выполните ДЗ; 5. Сделайте Pull Request в мастер моего репозитория; -6. Напишите мне в личные сообщения дискорда ссылку на PR. \ No newline at end of file +6. Напишите мне в личные сообщения дискорда ссылку на PR. + +## Паттерны + +1. Порождающие +1. Структурные +1. Поведенческие + +## Порождающие + +Помогают организовать гибкое создание сущностей(чаще объектов). Уменьшаю зависимости. + +1. Абстрактная фабрика (Abstract Factory) +1. Строитель(Builder) +1. Фабричный метод (Factory method) +1. Прототип (Prototype) +1. Одиночка (Singleton) + +### Абстрактная фабрика (Abstract Factory) + +#### Описание + +Паттерн позволяющий создавать семейства сущностей без жесткой завязки на конкретную реализацию(классы). + +#### Когда применяю + +Применяю если в проекте есть семейства сущностей(наборы сущностей). Количество и тип сущностей в каждом наборе одинаковые, но различается реализация. + +Набор 1: + +1. Кнопка +1. Инпут +1. Таблица + +Набор 2: + +1. Кнопка Мобильная +1. Инпут Мобильный +1. Таблица Мобильная + +Таким образом мы можем менять фабрику в зависимости от типа устройства(мобильное, десктоп). Таким образом мы только в одном месте определим какую фабрику выбрать и в других местах просто использовать ее. + +### Частота использования + +Редко + +### Строитель(Builder) + +#### Описание + +Позволяет создавать сложные объекты пошагово. + +#### Когда применяю + +Если мне необходимо формировать какой-то конфиг динамически, либо динамически нужно сформировать форму, либо я реализую степпер, где пользователь шаг за шагом заполняет большую форму. То я сразу смотрю в сторону билдера. Если нужно собрать сложный/большой объект - билдер. + +### Частота использования + +Часто + +### Фабричный метод (Factory method) + +#### Описание + +Паттерн позволяющий подменять реализацию создаваемой сущности. + +#### Когда применяю + +Фабрика набор методов для создания набора сущностей. Фабричный метод - метод для создания сущностей. Главное чтобы эти сущности описывались одним интерфейсом. Применяю тогда, когда у меня есть несколько сущностей, они взаимозаменяемые, нужно динамически их создавать, выбирая в зависимости от условий. + +### Частота использования + +Редко + +### Прототип (Prototype) + +#### Описание + +Паттерн позволяющий создавать сущность на основе другой сущности. + +#### Когда применяю + +Применяю, когда мне необходимо создавать сущности по шаблону. Например: создание коллекции с фильмами. Создание формы фидбека и тд. У меня в проекте есть прототип, когда пользователь хочет создать новую коллекцию, написать новый отзыв, то я просто копирую прототип с дефолтными значениями и потом пользователь уже заполняет сам то, что нужно. + +### Частота использования + +Средне + +### Одиночка (Singleton) + +#### Описание + +Паттерн позволяющий создать только один экземпляр. + +#### Когда применяю + +Если я слышу, что что-то должно быть в единственном числе - синглтон. Один экземпляр движка плеера, одна фабрика создания рекламных баннеров, один логгер, один чат поддержки, один экземпляр сервиса(часто в DI). + +### Частота использования + +Часто + +## Структурные + +Помогают организовать иерархие сущностей без лишних жестких зависимостей. + +1. Адаптер (Adapter) +1. Мост (Bridge) +1. Компоновщик (Composite) +1. Декоратор (Decorator) +1. Фасад (Facade) +1. Легковес (Flyweight) +1. Заместитель (proxy) + +### Адаптер (Adapter) + +#### Описание + +Паттерн позволяющий адаптировать реализацию под интерфейс без внесения в нее изменений. + +#### Когда применяю + +Если у меня есть несколько реализаций чего-то(плеерных движков, логгеров и тп). Мне хочется чтобы в приложении с ними могли работать одинаково, чтобы специфичная логика не расползалась. Я реализую адаптеры, которые позволяют адаптировать эти реализации под интерфейс. +Если я вижу, что мы ждём сущность соответствующую интерфейсу, но в библиотеки, которую мы используем эта сущность с другим интерфейсом, то я адаптирую ее под наш интерфейс. Там могут быть просто другие названия методов и тп. В адаптере будет логика адаптирования под наш интерфейс. + +### Частота использования + +Часто + +### Мост (Bridge) + +#### Описание + +Паттерн позволяющий разделить реализацию и абстракцию на две иерархии, что позволяет их развивать независимо. + +#### Когда применяю + +Если я вижу, что есть какой-то класс, сущность или модуль, но одна из его частей изменяется чаще других, то можно ее вынести и организовать взаимодействие на уровне интерфейсов, таким образом мы сможем менять реализацию этой части, подменять ее и тд без вреда для основной неизменяемой. + +### Частота использования + +Средне + +### Компоновщик (Composite) + +#### Описание + +Паттерн позволяющий сгруппировать объекты в дерево и работать с ними как с одним. + +#### Когда применяю + +Если я мне необходимо работать с графами, либо с структурой близкой к дереву, либо которую можно представить как дерево, то я сразу думаю о возможности использования этого паттерна. + +### Частота использования + +Редко + +### Декоратор (Decorator) + +#### Описание + +Паттерн позволяющий добавить новой логики к уже имеющимся методам, реализации. + +#### Когда применяю + +Если мне нужно гибко добавлять новую логику к уже имеющийся, то я могу либо сделать кучу ифаков, либо сделать декоратор, декоратор лучше, тк не усложняет логику и можно динамически менять декораторы. + +### Частота использования + +Очень часто + +### Фасад (Facade) + +#### Описание + +Паттерн позволяющий просто работать со сложной реализацией или группой реализаций. + +#### Когда применяю + +Если у меня есть сложный механизм, сложная реализация, иногда даже состоящая из нескольких частей, то я думаю о фасаде. Фасад позволяет скрыть сложность от пользователя(конечный пользователь, другие разработчики) и работать просто с чем-то сложным + +### Частота использования + +Часто + +### Легковес (Flyweight) + +#### Описание + +Паттерн позволяющий экономить память и уменьшать сложность. + +#### Когда применяю + +Если я замечаю, что у многих объектов есть одинаковая часть, которая и изменяется одинаково, например, пользователь, то я просто выношу пользователя в один объект и все остальные ссылаются на него, а не хранят каждый у себя. + +### Частота использования + +Часто + +### Посредник (Proxy) + +#### Описание + +Паттерн - секретарь. Позволяет сделать что-то до/после вызова реального метода объекта. + +#### Когда применяю + +Если мне нужно гибко управлять доступом к частям объекта, то я выношу такую логику в проксю, что позволяет не усложнять сам объект. А в прксе уже идут проверки и тп. Еще проксе можно организовать логгирование, кеширование, предзагрузку и тп. + +### Частота использования + +Средне + +## Поведенческие + +Помогают организовать гибкое взаимодействие между сущностями. + +1. Цепочка обязанностей (Chain of responsibility) +1. Команда (Command) +1. Итератор (Iterator) +1. Посредник (Mediator) +1. Снимок, сохранение (Memento) +1. Наблюдатель (Observer) +1. Состояние (State) +1. Стратегия (Strategy) +1. Шаблонный метод (Template method) +1. Посетитель (Visitor) + +### Цепочка обязанностей (Chain of responsibility) + +#### Описание + +Паттерн позволяющий разделить логику между обработчиками и выполнять ее последовательно. + +#### Когда применяю + +Использую если нужно организовать логику сложной проверки. Ярким примером являются мидлвары в редаксе. + +### Частота использования + +Средне + +### Команда (Command) + +#### Описание + +Паттерн позволяющий превратить действие в объект. Это позволяет организовывать очереди, логику отмены. + +#### Когда применяю + +Использую если нужно фиксировать каждое действие пользователя, чтобы иметь возможность работать с историей. Яркий пример - работа с браузерным апи, каждый переход это команда, которая складывается в историю и мы можем вернуться на любой участок истории. (так работают почти все клиентские роутеры) + +### Частота использования + +Средне + +### Итератор (Iterator) + +#### Описание + +Паттерн позволяющий организовать обход коллекции, без знаний о ее внутренней структуре. + +#### Когда применяю + +Если работаю с какой-то кастомной коллекцией(не массив), например linked list, queue и что-то подобное, то там реализую итератор, чтобы комфортнее и проще обходить их. + +### Частота использования + +Средне + +### Посредник (Mediator) + +#### Описание + +Паттерн позволяющий уменьшить связанность между несколькими сущностями. + +#### Когда применяю + +Если у меня есть ворох объектов/сущностей/модулей и они взаимодействуют другом с другом напрямую, то в будущем это может привести к циклическим зависимостям, избыточной связанности и тп. В этих случаях я реализую сущность-посредник, который отвечает за работу с этими связями, а сами сущности работают только с ним. + +### Частота использования + +Часто + +### Снимок, сохранение (Memento) + +#### Описание + +Паттерн позволяющий делать сохранений объекта, прошлые состояния и восстанавливать их без погружения пользователя в детали реализации. + +#### Когда применяю + +Если необходимо реализовать логику отмены изменений в рамках одного состояния/объекта, то я выберу снимок, а не команду, тк команда нечто более глобальное(затрагивает много частей, много состояний), снимок более локальное. + +### Частота использования + +Редко + +### Наблюдатель (Observer) + +#### Описание + +Паттерн позволяющий подписываться на изменений/события и сразу же реагировать на них. + +#### Когда применяю + +Если необходимо следить за изменениями(стор редакса как пример), следить за событиями(браузерные ивенты) и тп, то тут этот паттерн отлично подходит, только не забывайте отписываться. Основная идея в том, что мы уходим от постоянного опрашивания, теперь нас оповещают о изменениях/событиях + +### Частота использования + +Часто + +### Состояние (State) + +#### Описание + +Паттерн позволяющий менять поведение в зависимости от состояния. + +#### Когда применяю + +Ярким примером является плеер. Если фильм играет, то контролы ведут себя одним образом, если на паузе другим, если проигрывание закончилось третьим. Основная идея в том, что если наша сущность может быть в нескольких состояниях(режим редактирования и просмотра, проигрывание и пауза, ограниченный режим и полный доступ и тп), то стоит обратить внимание на этот паттерн. + +### Частота использования + +Средне + +### Стратегия (Strategy) + +#### Описание + +Паттерн позволяющий менять алгоритм динамически. + +#### Когда применяю + +Определяем семейство алгоритмов(сортировки таблицы, способы логгирования, способы фильтрации) и динамически их меняем. Самое важное, что интерфейс реализации алгоритма не меняется, меняется только логика внутри. Была сортировка по убыванию, стало по возрастанию и тд. + +### Частота использования + +Часто + +### Шаблонный метод (Template method) + +#### Описание + +Паттерн позволяющий определить структуру алгоритма, реализации давая возможность в подклассах реализовать детали. + +#### Когда применяю + +Если у меня есть алгоритм, но в каждом подклассе меняется его реализация, то я использую шаблонный метод. Яркий пример абстрактный метод в в тайпскрипте. Используя его мы определяем интерфейс, но реализацию пишут подклассы. + +### Частота использования + +Редко + +### Посетитель (Visitor) + +#### Описание + +Паттерн позволяющий внедрить объект в другие, который может выполнять операции над ними. + +#### Когда применяю + +Если мне необходимо првоести схожие операции над большим количеством объектов коллекции или тп, то я реализую посетитель и он посещает все необходимы объекты(хорошо работает в связке с итератором) и выполняет операцию. Например переименование файлов, замена импортов, печать частей коллекции и тд, что-то однообразное, но в разных местах. + +### Частота использования + +Редко diff --git a/src/patterns/01-abstractFactory/index.js b/src/patterns/01-abstractFactory/index.js index 6747591..4203c9c 100644 --- a/src/patterns/01-abstractFactory/index.js +++ b/src/patterns/01-abstractFactory/index.js @@ -5,18 +5,36 @@ export class ErrorNotification {} export class SuccessControl { create (type = '') { - // todo: implement logic + if (type === 'button') { + return new SuccessButton(); + } + + if (type === 'notification') { + return new SuccessNotification(); + } } } export class ErrorControl { create (type = '') { - // todo: implement logic + if (type === 'button') { + return new ErrorButton(); + } + + if (type === 'notification') { + return new ErrorNotification(); + } } } export default class ControlsFactory { getFactory (factoryType = '') { - // todo: implement logic + if (factoryType === 'success') { + return new SuccessControl(); + } + + if (factoryType === 'error') { + return new ErrorControl(); + } } } diff --git a/src/patterns/02-builder/index.js b/src/patterns/02-builder/index.js index 8d7f02c..94e9b5d 100644 --- a/src/patterns/02-builder/index.js +++ b/src/patterns/02-builder/index.js @@ -4,14 +4,24 @@ export default class RequestBuilder { } addPagination (start, end) { - // todo: implement logic + this.url.searchParams.append('start', start); + this.url.searchParams.append('end', end); + + return this; } addSort (sort, order) { - // todo: implement logic + this.url.searchParams.append('sort', sort); + this.url.searchParams.append('order', order); + + return this; } addFilter (filter, filterLte, filterGte) { - // todo: implement logic + this.url.searchParams.append('filter', filter); + this.url.searchParams.append('filter_lte', filterLte); + this.url.searchParams.append('filter_gte', filterGte); + + return this; } } diff --git a/src/patterns/03-factoryMethod/index.js b/src/patterns/03-factoryMethod/index.js index a299f29..dec8efd 100644 --- a/src/patterns/03-factoryMethod/index.js +++ b/src/patterns/03-factoryMethod/index.js @@ -7,17 +7,29 @@ class Input { } export class TextInput extends Input { - // todo: implement logic + static create() { + return new TextInput(); + } } export class NumberInput extends Input { - // todo: implement logic + static create() { + return new NumberInput(); + } } export class EmailInput extends Input { - // todo: implement logic + static create() { + return new EmailInput(); + } } export const inputFactory = (type = '') => { - // todo: implement logic + const inputs = { + text: TextInput, + number: NumberInput, + email: EmailInput, + } + + return inputs[type].create(); }; diff --git a/src/patterns/04-prototype/index.js b/src/patterns/04-prototype/index.js index 208269d..425a8da 100644 --- a/src/patterns/04-prototype/index.js +++ b/src/patterns/04-prototype/index.js @@ -1,5 +1,7 @@ class Monster { - // todo: implement logic + constructor(settings) { + this.settings = settings; + } } export default class Location { @@ -7,14 +9,28 @@ export default class Location { constructor(name = '', monstersCount = 0, monstersSettings = {}) { this.name = name; - // todo: implement logic + this.monstersCount = monstersCount; + this.monstersSettings = monstersSettings; + } + + get monstersSettings() { + return this._settings; + } + + set monstersSettings(value) { + this._settings = value; + this.initMonsters(); } initMonsters () { - // todo: implement logic + const newMonsters = []; + for(let i = 0; i < this.monstersCount; i++) { + newMonsters.push(new Monster(this._settings)); + } + this.monsters = newMonsters; } clone () { - // todo: implement logic + return new Location(this.name, this.monstersCount, { ...this._settings }); } } diff --git a/src/patterns/05-singleton/index.js b/src/patterns/05-singleton/index.js index 0927bab..584612a 100644 --- a/src/patterns/05-singleton/index.js +++ b/src/patterns/05-singleton/index.js @@ -1,5 +1,11 @@ export default class Singleton { + static instance; + constructor() { - // todo: implement logic + if (Singleton.instance) { + return Singleton.instance; + } + + Singleton.instance = this; } } diff --git a/src/patterns/06-adapter/index.js b/src/patterns/06-adapter/index.js index a61bc05..0e553a0 100644 --- a/src/patterns/06-adapter/index.js +++ b/src/patterns/06-adapter/index.js @@ -17,7 +17,8 @@ export class Rectangle { export class Adapter { constructor(shape) { - // todo: add implementation + this.width = shape.size; + this.height = shape.size; } } diff --git a/src/patterns/07-bridge/index.js b/src/patterns/07-bridge/index.js index 0c5419e..0f07d27 100644 --- a/src/patterns/07-bridge/index.js +++ b/src/patterns/07-bridge/index.js @@ -11,8 +11,9 @@ export class GreenColorsPallet { } export class Notification { - constructor () { - // todo: add implementation + constructor (name, pallet) { + this.name = name; + this.colorsPallet = pallet; } toString () { diff --git a/src/patterns/08-composite/index.js b/src/patterns/08-composite/index.js index b41c387..79bda9a 100644 --- a/src/patterns/08-composite/index.js +++ b/src/patterns/08-composite/index.js @@ -4,7 +4,7 @@ export class Child { } getSum () { - // todo: add implementation + return this.value; } } @@ -14,7 +14,7 @@ export class Parent { } getSum () { - // todo: add implementation + return this.values.reduce((acc, value) => acc + value.getSum(), 0); } } diff --git a/src/patterns/09-decorator/index.js b/src/patterns/09-decorator/index.js index 0c1ee33..f2fe9a3 100644 --- a/src/patterns/09-decorator/index.js +++ b/src/patterns/09-decorator/index.js @@ -1,13 +1,26 @@ export class Milk { price = 2; - // todo: add implementation + constructor (extra) { + this.extra = extra; + } + + getPrice () { + return this.extra ? this.extra.getPrice() + this.price : this.price; + } } export class Sugar { price = 1; - // todo: add implementation + // Смущает что получилось два одинаковых решения для Milk и для Sugar + constructor (extra) { + this.extra = extra; + } + + getPrice () { + return this.extra ? this.extra.getPrice() + this.price : this.price; + } } export class Coffee { diff --git a/src/patterns/10-facade/index.js b/src/patterns/10-facade/index.js index 0f6321d..8566020 100644 --- a/src/patterns/10-facade/index.js +++ b/src/patterns/10-facade/index.js @@ -1,6 +1,14 @@ export class Game { + constructor() { + this.hero = new Hero(); + this.location = new Location(); + } start () { - // todo: add implementation + this.hero.name = 'Barbarian'; + this.location.name = 'darkForest'; + this.location.addMonster(new Monster('demon')); + this.location.addMonster(new Monster('demon')); + this.location.addMonster(new Monster('undead')); } } diff --git a/src/patterns/11-flyweight/index.js b/src/patterns/11-flyweight/index.js index a44aa44..7890f29 100644 --- a/src/patterns/11-flyweight/index.js +++ b/src/patterns/11-flyweight/index.js @@ -1,5 +1,9 @@ class Flyweight { - // todo: add implementation + constructor(name, country, color) { + this.name = name; + this.country = country; + this.color = color; + } } export class ProductsStore { @@ -9,10 +13,18 @@ export class ProductsStore { addProduct (productData = {}) { const productFlyweight = this.getOrCreateFlyweight(productData.info); - // todo: add implementation + this.products.push({ + ...productData, + info: productFlyweight, + }); } getOrCreateFlyweight (info = {}) { - // todo: add implementation + const flyweightKey = `${info.name}${info.country}${info.color}`; + if (!this.flyweights[flyweightKey]) { + this.flyweights[flyweightKey] = info; + } + + return this.flyweights[flyweightKey]; } } diff --git a/src/patterns/12-proxy/index.js b/src/patterns/12-proxy/index.js index 0672507..068003a 100644 --- a/src/patterns/12-proxy/index.js +++ b/src/patterns/12-proxy/index.js @@ -10,14 +10,19 @@ export class User { } export class ProxyUser { + // Не понимаю зачем здесь это свойство rights = []; - constructor() { - // todo: add implementation + constructor(user) { + this.user = user; } write () { - // todo: add implementation + if (this.user.rights.includes('admin')) { + return this.user.write(); + } + + return "user does not have permissions to write"; } } diff --git a/src/patterns/13-chainOfResponsibility/index.js b/src/patterns/13-chainOfResponsibility/index.js index d0af96a..68dfaec 100644 --- a/src/patterns/13-chainOfResponsibility/index.js +++ b/src/patterns/13-chainOfResponsibility/index.js @@ -1,17 +1,29 @@ class Handler { name = ''; regExp = /./; + nextHandler; setNext (handler) { - // todo: implement + this.nextHandler = handler; + return this.nextHandler; } next (data) { - // todo: implement + if (this.nextHandler) { + return this.nextHandler?.validate(data); + } } validate (data) { - // todo: implement + if (this.regExp.test(data)) { + /* + Непонятно для чего нужно свойство next, если можно записать короче: + return this.nextHandler?.validate(data); + */ + return this.next(data); + } + + return `Validation rule \"${this.name}\" didn\'t pass for string \"${data}\"`; } } diff --git a/src/patterns/14-command/index.js b/src/patterns/14-command/index.js index 2282d95..46e62ad 100644 --- a/src/patterns/14-command/index.js +++ b/src/patterns/14-command/index.js @@ -1,12 +1,20 @@ export class NextPage { + constructor(pagination) { + this.pagination = pagination; + } + execute () { - // todo: add implementation + this.pagination.nextPage(); } } export class PrevPage { + constructor(pagination) { + this.pagination = pagination; + } + execute () { - // todo: add implementation + this.pagination.prevPage(); } } @@ -24,10 +32,10 @@ export class Pagination { export class Button { constructor (command) { - // todo: add implementation + this.onClick = command; } click () { - // todo: add implementation + this.onClick.execute(); } } diff --git a/src/patterns/15-iterator/index.js b/src/patterns/15-iterator/index.js index 360fbc6..740b15e 100644 --- a/src/patterns/15-iterator/index.js +++ b/src/patterns/15-iterator/index.js @@ -5,11 +5,18 @@ export class Range { } forEach (callback) { - // todo: add implementation + for(let i = this.start; i <= this.end; i++) { + callback(i); + } } getRange () { - // todo: add implementation + const array = []; + this.forEach((number) => { + array.push(number); + }) + + return array; } } diff --git a/src/patterns/16-mediator/index.js b/src/patterns/16-mediator/index.js index 5d7339a..a77abb4 100644 --- a/src/patterns/16-mediator/index.js +++ b/src/patterns/16-mediator/index.js @@ -7,7 +7,7 @@ export class BillSharing { } addParticipant (participant) { - // todo: add implementation + this.participants.push(participant); } getPaymentAmount() { @@ -19,11 +19,16 @@ export class BillSharing { } share () { - // todo: add implementation + this.participants.forEach((participant) => { + participant.pay(); + }); } borrow (amount = 0) { - // todo: add implementation + const participantsWithCash = this.participants.filter((participant) => participant.cash > 0); + participantsWithCash.forEach((participant) => { + participant.pay(amount / participantsWithCash.length); + }); } } @@ -34,11 +39,19 @@ export class User { this.billSharing = billSharing; } - pay () { - // todo: add implementation + pay (amount = this.billSharing.getPaymentAmount()) { + if (this.cash >= amount) { + this.cash -= amount; + this.billSharing.pay(amount); + } else { + const debt = amount - this.cash; + this.billSharing.pay(this.cash); + this.cash = 0; + this.borrow(debt); + } } borrow (amount = 0) { - // todo: add implementation + this.billSharing.borrow(amount); } } diff --git a/src/patterns/17-memento/index.js b/src/patterns/17-memento/index.js index 0233005..0ea70d3 100644 --- a/src/patterns/17-memento/index.js +++ b/src/patterns/17-memento/index.js @@ -1,9 +1,21 @@ +// Непонятно для чего здесь класс Memento, раз нам не важно реализация состояния класса Hero, +// то можно просто хранить состояние как строку. export class Memento { // todo: add implementation } export class History { - // todo: add implementation + snapshots = []; + + save (snapshot) { + return (this.snapshots.push(snapshot) - 1); + } + + restore (key) { + if (this.snapshots[key]) { + return this.snapshots[key]; + } + } } export class Hero { @@ -31,11 +43,15 @@ export class Hero { this.#state.level += 1; } - load (snapshot = {}) { - // todo: add implementation + load (snapshot) { + const rawState = this.history.restore(snapshot); + if (rawState) { + const state = JSON.parse(rawState); + this.#state = state; + } } save () { - // todo: add implementation + return this.history.save(JSON.stringify(this.#state)); } } diff --git a/src/patterns/18-observer/index.js b/src/patterns/18-observer/index.js index 6474671..233bebe 100644 --- a/src/patterns/18-observer/index.js +++ b/src/patterns/18-observer/index.js @@ -2,11 +2,11 @@ export class NewsChannel { users = []; subscribe (user) { - // todo: add implementation + this.users.push(user); } notify (message = '') { - // todo: add implementation + this.users.forEach((user) => user.receiveMessage(message)); } } @@ -18,6 +18,6 @@ export class User { } receiveMessage (message = '') { - // todo: add implementation + this.messagesHistory.push(message); } } diff --git a/src/patterns/19-state/index.js b/src/patterns/19-state/index.js index 4d1d588..e730d09 100644 --- a/src/patterns/19-state/index.js +++ b/src/patterns/19-state/index.js @@ -28,19 +28,36 @@ class OldDigitalLock { } class Locked { - // todo: add implementation + constructor(key, lock) { + this.status = 'locked'; + this.lock = lock; + this.key = key; + } + + toggle (combination = '') { + if (combination === this.key) { + this.lock.state = new Unlocked(this.lock); + } + } } class Unlocked { - // todo: add implementation + constructor(lock) { + this.status = 'unlocked'; + this.lock = lock; +} + + toggle (combination = '') { + this.lock.state = new Locked(combination, this.lock); + } } export class DigitalLock { constructor(key = "") { - // todo: add implementation + this.state = new Locked(key, this); } toggle (combination = '') { - // todo: add implementation + this.state.toggle(combination); } } diff --git a/src/patterns/20-strategy/index.js b/src/patterns/20-strategy/index.js index 1daaf22..cc61c01 100644 --- a/src/patterns/20-strategy/index.js +++ b/src/patterns/20-strategy/index.js @@ -10,7 +10,7 @@ export class Sword { speed = 1; damage = 15; attack (monster) { - // todo: add implementation + return this.damage * this.speed - monster.armor; } } @@ -18,18 +18,18 @@ export class MagicWand { speed = 2; damage = 8; attack (monster) { - // todo: add implementation + return this.damage * this.speed - monster.armor; } } export class Hero { - constructor(name) { + constructor(name, weapon) { this.name = name; - // todo: add implementation + this.weapon = weapon } hit (monster) { - // todo: add implementation + return this.weapon.attack(monster); } } diff --git a/src/patterns/21-templateMethod/index.js b/src/patterns/21-templateMethod/index.js index 36fadeb..9396a79 100644 --- a/src/patterns/21-templateMethod/index.js +++ b/src/patterns/21-templateMethod/index.js @@ -1,66 +1,57 @@ class HotDrinksPot { - // todo: add implementation -} - -// todo: make refactoring via template method pattern -export class TeaPot { - algorithmSteps = {}; - constructor() { + this.algorithmSteps = {}; this.prepareRecipe(); } - prepareRecipe () { + prepareRecipe() { this.boilWater(); - this.brewTea(); + this.brew(); this.pourInCup(); - this.addLemon(); + this.addCondiments(); + } +} + +export class TeaPot extends HotDrinksPot { + constructor() { + super(); } boilWater () { this.algorithmSteps.boilWater = 'Boiling water'; } - brewTea () { - this.algorithmSteps.brewTea = 'Steeping the tea'; + brew () { + this.algorithmSteps.brew = 'Steeping the tea'; } pourInCup () { this.algorithmSteps.pourInCup = 'Pouring into cup'; } - addLemon () { - this.algorithmSteps.addLemon = 'Adding Lemon'; + addCondiments () { + this.algorithmSteps.addCondiments = 'Adding Lemon'; } } -export class CoffeePot { - algorithmSteps = {}; - +export class CoffeePot extends HotDrinksPot { constructor() { - this.prepareRecipe(); - } - - prepareRecipe () { - this.boilWater(); - this.brewCoffee(); - this.pourInCup(); - this.addSugarAndMilk(); + super(); } boilWater () { this.algorithmSteps.boilWater = 'Boiling water'; } - brewCoffee () { - this.algorithmSteps.brewCoffee = 'Dripping Coffee through filter'; + brew () { + this.algorithmSteps.brew = 'Dripping Coffee through filter'; } pourInCup () { this.algorithmSteps.pourInCup = 'Pouring into cup'; } - addSugarAndMilk () { - this.algorithmSteps.addSugarAndMilk = 'Adding Sugar and Milk'; + addCondiments () { + this.algorithmSteps.addCondiments = 'Adding Sugar and Milk'; } } diff --git a/src/patterns/22-visitor/index.js b/src/patterns/22-visitor/index.js index f8228d2..d21c954 100644 --- a/src/patterns/22-visitor/index.js +++ b/src/patterns/22-visitor/index.js @@ -7,11 +7,17 @@ export class Visitor { init () { this.addGetSize(); + // Непонятно какая дополнительная логика должна быть добавлена // todo: add implementation } addGetSize () { - // todo: add implementation + this.compositeItem.getSize = () => { + return this.compositeItem.children.reduce((acc, child) => { + child.accept(Visitor); + return acc + child.getSize(); + }, 1); + } } }