[Разработка веб-сайтов, JavaScript, Программирование, Совершенный код] Как выдать Золушку за принца и не сойти с ума. Паттерн Декоратор

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
29-Апр-2021 13:32

Всем привет, я Максим Кравец из Holyweb, и мы продолжаем разговор о паттернах (первую статью о Singleton можно почитать вот тут). Героя нашего сегодняшнего сюжета порой называют «wrapper» или «обертка», поскольку он оборачивает исходный код, но мне больше нравится название «декоратор» — оно точнее отражает не механику, а суть происходящего. Приступим.
А кто у нас муж? Волшебник? Предупреждать же надо!Хорошо Золушке — у нее тетя не просто так крестная, а целая добрая фея. Взмах волшебной палочки — и тыква превращается в карету. Еще взмах — и рабочая одежда становится бальным платьем. Две минуты волшебства — и у любого принца шансы отвертеться устремляются к нулю. Мы, конечно, не волшебники. Мы программисты. Но творить чудеса для нашего кода обязаны! Так что создаем класс «Золушка», наделяем ее ангельским характером и пытаемся выдать ее замуж, по возможности — удачно.
class Cinderella {
aboutMe() {
     return `ангельский характер`;
};
}
Пришла пора посмотреть на потенциальных супругов:
  • Принц Филипп. Обожает скачки, охоту, экстремальный отдых.
  • Принц Эдвард. Страстный поклонник танцев и бальных нарядов.
  • Принц Артур. Любитель сладостей и выпечки.
Давайте представим нашу Золушку принцу Филлипу:
class Cinderella {
aboutMe() {
     return `ангельский характер`;
};
}
const whatPrinceFilippKnows = new Cinderella()
console.log('У Золушки', whatPrinceFilippKnows.aboutMe())
Результат выполнения нашего кода:
У Золушки ангельский характер
Хм… маловато будет. Принц Филипп экстремал, с ним и встретиться-то можно только во время прыжка с тарзанки. На всякий случай добавим:
class Cinderella {
aboutMe() {
     return `ангельский характер`;
};
}
class ExtremeCinderella extends Cinderella {
  aboutMe() {
    return `
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ангельский характер
    `
  };
}
const whatPrinceFilippKnows = new ExtremeCinderella()
console.log('У Золушки', whatPrinceFilippKnows.aboutMe())
Пожалуй, такой результат нашего принца удовлетворит:
У Золушки
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ангельский характер
А вот принцу Эдварду экстрим — до лампочки. Он обожает танцы. Сделаем и ему Золушку его мечты, заодно немного поправим вывод в консоль, чтобы понимать, какому принцу какое счастье достанется:
class Cinderella {
  aboutMe() {
    return `ангельский характер`
  };
}
class ExtremeCinderella extends Cinderella {
  aboutMe() {
    return `
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ангельский характер
    `
  };
}
class DanceCinderella extends Cinderella {
  aboutMe() {
    return `
    свой магазин платьев и обуви "Все для бала"
    ангельский характер
    `
  };
}
const whatPrinceFilippKnows = new ExtremeCinderella()
const whatPrinceEdvardKnows = new DanceCinderella()
console.log('Принц Филипп знает, что у Золушки', whatPrinceFilippKnows.aboutMe())
console.log('Принц Эдвард знает, что у Золушки', whatPrinceEdvardKnows.aboutMe())
Результат выглядит вроде бы неплохо:
Принц Филипп знает, что у Золушки
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ангельский характер
Принц Эдвард знает, что у Золушки
    свой магазин платьев и обуви «Все для бала»
    ангельский характер
Хьюстон, у нас проблема! Даже две Первая — идеологическая. Вернемся ненадолго к опыту тети-феи, которая собирала свою крестницу на бал. Золушка — какой была изначально, такой и оставалась. В нее саму никаких изменений не вносилось! Изменялся только антураж, декорирование. Добавлялась одежда, карета, кучер, туфельки. Но Золушка оставалась Золушкой. Мы же — плодим новые классы с помощью наследования.Вторая проблема — принцев на свете многовато. И запросы у них порой... самые причудливые. Устанешь для каждого создавать отдельный класс. Хочется как в сказке: Золушка отдельно, платье отдельно, тыква, пардон, карета — тем более отдельно. Сложить все в коробку да и выдать ее принцу, пусть сам собирает тот комплект, что его устроит! Золушка и туфельки, Золушка и образование, Золушка и месть гномов… Впрочем, это уже про другое, нас же интересует, как реализовать задуманное. Для начала, давайте вынесем все «дополнительные опции» в отдельные функции. Вторым шагом (волшебники мы или погулять вышли?) прикажем этим функциям обернуть — задекорировать — свойства нашей исходной Золушки, чтобы при обращении к классу Cinderella возвращался не только ее ангельский характер, но и обертка. Согласно Википедии, Декоратор — структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту. Шаблон Декоратор предоставляет гибкую альтернативу практике создания подклассов с целью расширения функциональности.На первый взгляд — вроде бы то, что доктор прописал! Осталось понять, как это реализовать. Наследование не подошло, может быть получится с агрегацией (в более строгой форме — композицией)? 
Давайте еще раз внимательно взглянем на базовый класс Золушки и передадим в нашу функцию-обертку ссылку на базовый класс, а также реализуем точно такой же интерфейс. В итоге мы не будем наследовать поведение, мы добавим в обертке ее функционал, а базовую работу попросим выполнить переданную ссылку на класс.
class Cinderella {
  aboutMe() {
    return `ангельский характер`
  };
}
function extremeSet(cinderella) {
  this.aboutMe = function () {
    return `
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ${cinderella.aboutMe()}
    `
  }
}
function danceShop(cinderella) {
  this.aboutMe = function () {
    return `
    свой магазин платьев и обуви "Все для бала"
    ${cinderella.aboutMe()}
    `
  }
}
function pastryСhef(cinderella) {
  this.aboutMe = function () {
    return `
    диплом кондитера высшей категории
    ${cinderella.aboutMe()}
    `
  }
}
const whatPrinceFilippKnows =new extremeSet(new Cinderella())
const whatPrinceEdvardKnows = new danceShop(new Cinderella())
const whatPrinceArturKnows = new pastryСhef(new Cinderella())
const whatPrinceAliKnows = new extremeSet(new danceShop(new pastryСhef(new Cinderella())))
console.log('Принц Филипп знает, что у Золушки', whatPrinceFilippKnows.aboutMe())
console.log('Принц Эдвард знает, что у Золушки', whatPrinceEdvardKnows.aboutMe())
console.log('Принц Артур знает, что у Золушки', whatPrinceArturKnows.aboutMe())
console.log('Принц Али знает, что у Золушки', whatPrinceAliKnows.aboutMe())
Пока мы пытались разобраться, что к чему, подъехал четвертый принц по имени Али, которому нравится все сразу. Но благодаря паттерну Декораторов мы просто собрали ему нужный набор:
Принц Филипп знает, что у Золушки
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ангельский характер
Принц Эдвард знает, что у Золушки
    свой магазин платьев и обуви "Все для бала"
    ангельский характер
Принц Артур знает, что у Золушки
    диплом кондитера высшей категории
    ангельский характер
Принц Али знает, что у Золушки
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    свой магазин платьев и обуви "Все для бала"
    диплом кондитера высшей категории
    ангельский характер
Ах эта свадьба, свадьба пела и плясалаИ это — работает! Смело отправляемся в школу волшебства за дипломом. Хотя… мало познакомить, свадьба-то тоже на наших плечах! Так что давайте не мешкая вооружимся все тем же паттерном Декоратор и посчитаем, во что нам это все обойдется.
class Cinderella {
  aboutMe() {
    return `ангельский характер`
  };
}
function extremeSet(cinderella) {
  this.aboutMe = function () {
    return `
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ${cinderella.aboutMe()}
    `
  }
}
function danceShop(cinderella) {
  this.aboutMe = function () {
    return `
    свой магазин платьев и обуви "Все для бала"
    ${cinderella.aboutMe()}
    `
  }
}
function pastryСhef(cinderella) {
  this.aboutMe = function () {
    return `
    диплом кондитера высшей категории
    ${cinderella.aboutMe()}
    `
  }
}
// минимальная стоимость свадьбы, просто посидеть с гостями
class Wedding {
  price() {
    return 1000
  }
}
// добавить свадебный торт
function weddingCake(wedding) {
  this.price = function () {
    return wedding.price() + 200
  }
}
// пригласить оркестр
function jazzBand(wedding) {
  this.price = function () {
    return wedding.price() + 500
  }
}
// приглашенная звезда из соседнего королевства
function superStar(wedding) {
  this.price = function () {
    return wedding.price() + 100500
  }
}
const whatPrinceFilippKnows = new extremeSet(new Cinderella())
const whatPrinceEdvardKnows = new danceShop(new Cinderella())
const whatPrinceArturKnows = new pastryСhef(new Cinderella())
const whatPrinceAliKnows = new extremeSet(new danceShop(new pastryСhef(new Cinderella())))
const weddingPrice = new superStar(new Wedding())
console.log('Принц Филипп знает, что у Золушки', whatPrinceFilippKnows.aboutMe())
console.log('Принц Эдвард знает, что у Золушки', whatPrinceEdvardKnows.aboutMe())
console.log('Принц Артур знает, что у Золушки', whatPrinceArturKnows.aboutMe())
console.log('Принц Али знает, что у Золушки', whatPrinceAliKnows.aboutMe())
console.log('Бюджет свадьбы', weddingPrice.price())
Остается только собраться с родственниками принца и вдумчиво обсудить необходимость торта, звезды и гостей. Благо для пересчета надо просто собрать новый набор оберток.
Принц Филипп знает, что у Золушки
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    ангельский характер
Принц Эдвард знает, что у Золушки
    свой магазин платьев и обуви "Все для бала"
    ангельский характер
Принц Артур знает, что у Золушки
    диплом кондитера высшей категории
    ангельский характер
Принц Али знает, что у Золушки
    любовь к экстремальному отдыху
    5 комплектов альпинистского снаряжения под кроватью
    свой магазин платьев и обуви "Все для бала"
    диплом кондитера высшей категории
    ангельский характер
Бюджет свадьбы 101500
...и жили они долго…Сказочные истории принято завершать фразой про долго и счастливо. Свою задачу —  организовать процесс презентации нашей Золушки потенциальному принцу — мы выполнили. Не отвертится. И даже возможные расходы посчитали! Насколько удалось при этом донести смысл и механику работы паттерна Декоратор, решать вам. Если есть интерес, пишите в комментариях — или ответим сразу, или развернем тему еще в одной статье. А если хотите познакомиться с нашей командой ближе, я всегда на связи в Телеграме @maximkravec. 
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_javascript, #_programmirovanie (Программирование), #_sovershennyj_kod (Совершенный код), #_design_patterns, #_jscript, #_javascript, #_singleton, #_decorator, #_wrapper, #_razrabotka_vebsajtov (
Разработка веб-сайтов
)
, #_javascript, #_programmirovanie (
Программирование
)
, #_sovershennyj_kod (
Совершенный код
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 13:13
Часовой пояс: UTC + 5