PageSourceSearch

https://solidbook.vercel.app/_next/static/chunks/pages/ocp/patterns-8fe941c575e50cb8.js

js solidbook.vercel.app collected 2026-10-03 07:27:59 UTC 27,327 bytes, 2 lines download raw bytes

1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[623],{7062:function(e,r,t){"use strict";t.r(r),t.d(r,{default:function(){return MDXContent},meta:function(){return c}});var n=t(9499),s=t(5893),o=t(1151),i=t(1214),a=t(6778);function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}function _objectSpread(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?ownKeys(Object(t),!0).forEach(function(r){(0,n.Z)(e,r,t[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):ownKeys(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})}return e}var c={title:"OCP | Шаблоны проектирования и приёмы рефакторинга",description:"Шаблоны проектирования и приёмы рефакторинга, которые помогают следовать принципу открытости-закрытости"},MDXLayout=function(e){var r=e.children;return(0,s.jsx)(i.Z,{meta:c,children:r})};function _createMdxContent(e){var r=_objectSpread(_objectSpread({a:"a",code:"code",h1:"h1",h2:"h2",li:"li",p:"p",pre:"pre",section:"section",ul:"ul"},(0,o.a)()),e.components);return(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h1,{children:"Шаблоны проектирования и приёмы рефакторинга"}),(0,s.jsx)(r.p,{children:"Соблюдать принцип открытости-закрытости помогают несколько шаблонов проектирования и приёмов рефакторинга."}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Абстрактная фабрика"}),(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.a,{href:"https://github.com/kamranahmedse/design-patterns-for-humans#-simple-factory",children:"Фабрика"})," — это сущность, которая создаёт другие сущности по заданным правилам, например, создаёт экземпляры классов или объекты."]}),(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/abstract-factory",children:"Абстрактная фабрика"})," — это фабрика, которая создаёт фабрики."]}),(0,s.jsx)(r.p,{children:"Этот шаблон позволяет создавать сущности без привязки к конкретным классам — то есть без привязки к реализации. Так добавление новых типов сущностей изменяет минимальное количество модулей."}),(0,s.jsxs)(r.p,{children:["Рассмотрим применение абстрактной фабрики на том же примере с отчётом, что ",(0,s.jsx)(r.a,{href:"/srp/in-ideal-world",children:"был у нас в разделе об SRP"}),"."]}),(0,s.jsx)(r.p,{children:"В этом примере работа для абстрактной фабрики — выбор класса, который будет заниматься форматированием."}),(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{className:"language-ts",children:"// Часть с интерфейсом `Formatter` и классами,\n// реализующими его, остаётся такой же.\n// Добавляется новый интерфейс, описывающий фабрику фабрик:\n\ninterface FormatterFactory {\n  createFormatter(data: ReportData): Formatter\n}\n\n// Метод `createFormatter` возвращает абстрактный интерфейс,\n// поэтому обе фабрики ниже взаимозаменяемы:\n\nclass HtmlFormatterFactory implements FormatterFactory {\n  createFormatter(data: ReportData) {\n    return new HtmlFormatter(data)\n  }\n}\n\nclass TxtFormatterFactory implements FormatterFactory {\n  createFormatter(data: ReportData) {\n    return new TxtFormatter(data)\n  }\n}\n\n// При конфигурации приложение выберет нужный\n// тип фабрики и будет работать с ним.\n// Коду приложения при этом будет не важно,\n// с какой фабрикой он будет работать,\n// потому что он будет зависеть от интерфейсов,\n// а не от конкретных классов:\n\nclass AppConfigurator {\n  reportType: ReportTypes\n\n  constructor(reportType: ReportTypes) {\n    this.reportType = reportType\n  }\n\n  configure(reportData: ReportData): FormatterFactory {\n    if (this.reportType === ReportTypes.Html) {\n      return new HtmlFormatterFactory(reportData)\n    }\n    else return new TxtFormatterFactory(reportData)\n  }\n}\n"})})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Вопросы"}),(0,s.jsx)(a.x,{name:"ocp-patterns-1"}),(0,s.jsx)(a.x,{name:"ocp-patterns-2"})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Стратегия"}),(0,s.jsxs)(r.p,{children:["В прошлом примере мы избавились от необходимости менять код форматеров при добавлении новых требований. Но вы могли заметить, что в методе ",(0,s.jsx)(r.code,{children:"configure"})," класса ",(0,s.jsx)(r.code,{children:"AppConfigurator"})," есть условие, которое проверяет тип формата для отчёта."]}
1),(0,s.jsxs)(r.p,{children:["По-хорошему, подобные условия ",(0,s.jsx)(r.a,{href:"https://softwareengineering.stackexchange.com/a/302782",children:"следует заменять"})," на динамический выбор нужных сущностей. С этим может помочь ещё один шаблон — ",(0,s.jsx)(r.a,{href:"https://github.com/kamranahmedse/design-patterns-for-humans#-strategy",children:"стратегия"}),"."]}),(0,s.jsx)(r.p,{children:"Этот шаблон позволяет менять настройки, конфигурацию или алгоритм в зависимости от ситуации и требований. В нашем случае стратегии мы отдадим выбор необходимой фабрики:"}),(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{className:"language-ts",children:"function formatterStrategy(reportType: ReportTypes) {\n  const formatters = {\n    [ReportTypes.Html]: HtmlFormatterFactory,\n    [ReportTypes.Txt]: TxtFormatterFactory,\n    default: TxtFormatterFactory\n  }\n\n  return formatters[reportType] || formatters.default\n}\n"})}),(0,s.jsx)(r.p,{children:"Теперь выбор фабрик стал динамическим, и при изменении требований нам потребуется только добавить новую сущность и обновить список фабрик."})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Вопросы"}),(0,s.jsx)(a.x,{name:"ocp-patterns-3"}),(0,s.jsx)(a.x,{name:"ocp-patterns-4"})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Декоратор"}),(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/decorator",children:"Декоратор"})," — это шаблон, который заключается в создании обёрток с дополнительной функциональностью для объектов. Такие обёртки позволяют не изменять сам объект, но при этом расширять его функциональность."]}),(0,s.jsx)(r.p,{children:"Отличие декоратора от наследования в возможности расширять функциональность динамически, без необходимости описывать каждый класс-наследник отдельно."}),(0,s.jsxs)(r.p,{children:["В примере мы создаём класс ",(0,s.jsx)(r.code,{children:"BaseGreeting"}),", метод ",(0,s.jsx)(r.code,{children:"greet"})," которого будет выводить строку с приветствием пользователя. Декоратор ",(0,s.jsx)(r.code,{children:"GreetingWithUppercase"})," будет приводить строку с приветствием к верхнему регистру."]}),(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{className:"language-ts",children:"interface Greeting {\n  username: string\n  greet(): string\n}\n\n// Базовая функциональность описывается в классе,\n// который будет обёрнут с помощью декораторов:\n\nclass BaseGreeting implements Greeting {\n  username: string\n\n  constructor(username: string) {\n    this.username = username\n  }\n\n  greet(): string {\n    return `Hello, ${this.username}!`\n  }\n}\n\n// Здесь `decorated` — это объект,\n// функциональность которого мы будем расширять:\n\ninterface GreetingDecorator {\n  decorated: Greeting\n  greet(): string\n}\n\nclass GreetingWithUppercase implements GreetingDecorator {\n  decorated: Greeting\n\n  constructor(decorated: Greeting) {\n    this.decorated = decorated\n  }\n\n  greet(): string {\n    // 1. Используем базовое поведение:\n    const baseGreeting = this.decorated.greet()\n\n    // 2. Расширяем его:\n    return baseGreeting.toUpperCase()\n  }\n}\n"})}),(0,s.jsx)(r.p,{children:"Сама философия этого шаблона повторяет принцип открытости-закрытости — мы не меняем базовый класс, а добавляем сущности, которые содержат в себе изменения бизнес-требований."}),(0,s.jsxs)(r.p,{children:["Разница между декоратором и ",(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/proxy",children:"прокси"})," в том, что прокси всегда предоставляет тот же интерфейс, в то время как декоратор может предоставлять расширенный интерфейс."]})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Вопросы"}),(0,s.jsx)(a.x,{name:"ocp-patterns-5"}),(0,s.jsx)(a.x,{name:"ocp-patterns-6"})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Наблюдатель"}),(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/observer",children:"Наблюдатель"})," — шаблон, который создаёт механизм подписки, когда некоторые сущности могут реагировать на поведение других."]}),(0,s.jsxs)(r.p,{children:["В примере ниже у нас есть класс ",(0,s.jsx)(r.code,{children:"SoftwareEngineerApplicant"}),", который реагирует на появление вакансий в экземпляре класса ",(0,s.jsx)(r.code,{children:"HrAgency"}),"."]}),(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{className:"language-ts",children:"// Интерфейс соискателя описывает его имя и желаемую позицию:\n\ninterface Applicant {\n  name: string\n  position: string\n}\n\n// Интерфейс наблюдателя описывает метод,\n// который будет вызываться наблюдаемым объектом\n// при наступлении события:\n\ninterface Observer {\n  update(data: any): void\n}\n\ninterface NewPositionObserver extends Applicant, Observer {\n  update(position: string): void\n}\n\nclass SoftwareEngineerApplicant implements NewPositionObserver {\n  name: string\n  position: string\n\n  constructor(name: string, position: string) {\n    this.name = name\n    this.position = position\n  }\n\n  update(position: string) {\n    if (position !== this.position) return\n    console.log(`Hello! My name is ${this.name}, I would like to apply to a ${position} position`)\n  }\n}\n\n// Базовый интерфейс наблюдаемого объекта:\n\ninterface Observable {\n  subscribe(observer: Observer): void\n  unsubscribe(observer: Observer): void\n  notify(data: any): void\n}\n\n// Наблюдаемый объект хранит в себе список наблюдателей,\n// которых будет уведомлять о наступлении события:\n\ninterface NewPositionObservable extends Observable {\n  listeners: NewPositionObserver[]\n  notify(position: string): void\n}\n\nclass HrAgency implements NewPositionObservable {\n  listeners: NewPositionObserver[] = []\n\n  subscribe(applicant: NewPositionObserver): void {\n    this.listeners.push(applicant)\n  }\n\n  unsubscribe(applicant: NewPositionObserver): void {\n    this.listeners = this.listeners.filter(listener =>
1\n      listener.name !== applicant.name)\n  }\n\n  // Уведомляем всех наблюдателей,\n  // когда появляется новая вакансия:\n\n  notify(position: string): void {\n    this.listeners.forEach(listener => {\n      listener.update(position)\n    })\n  }\n}\n"})}),(0,s.jsx)(r.p,{children:"Этот шаблон позволяет добавлять новых наблюдателей без необходимости менять код наблюдаемого объекта."})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Вопросы"}),(0,s.jsx)(a.x,{name:"ocp-patterns-7"}),(0,s.jsx)(a.x,{name:"ocp-patterns-8"})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Замена прямого наследования на полиморфизм и композицию"}),(0,s.jsx)(r.p,{children:"Модули, зависящие от конкретных классов, связаны с ними слишком сильно, из-за чего изменение в одном модуле затронет изменение в другом."}),(0,s.jsxs)(r.p,{children:[(0,s.jsx)(r.a,{href:"https://blog.aspiresys.pl/technology/example-of-just-in-time-design-refactor-to-open-closed/",children:"Замена"})," прямого наследования на полиморфизм или композицию — это приём рефакторинга, который ослабляет зацепление модулей через введение абстракций: интерфейсов, обёрток и т.д."]}),(0,s.jsxs)(r.p,{children:["Примером может послужить ",(0,s.jsx)(r.a,{href:"/ocp/in-ideal-world",children:"пример"})," из раздела \xabВ идеальном мире\xbb, где мы вводили прослойку из интерфейса ",(0,s.jsx)(r.code,{children:"Shape"}),". Когда класс ",(0,s.jsx)(r.code,{children:"AreaCalculator"})," начинает зависеть от интерфейса, а не от конкретных классов, изменение в требованиях не затрагивает код класса ",(0,s.jsx)(r.code,{children:"AreaCalculator"}),"."]})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Вопросы"}),(0,s.jsx)(a.x,{name:"ocp-patterns-9"})]}),(0,s.jsxs)(r.section,{children:[(0,s.jsx)(r.h2,{children:"Материалы к разделу"}),(0,s.jsxs)(r.ul,{children:["\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://en.wikipedia.org/wiki/Composition_over_inheritance",children:"Composition over inheritance"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://github.com/kamranahmedse/design-patterns-for-humans#-simple-factory",children:"Фабрика"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/abstract-factory",children:"Абстрактная фабрика"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://github.com/torokmark/design_patterns_in_typescript/blob/master/abstract_factory/abstractFactory.ts",children:"Реализация абстрактной фабрики на TypeScript"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://github.com/kamranahmedse/design-patterns-for-humans#-strategy",children:"Стратегия"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://sergeyzhuk.me/2018/01/25/factory-method-and-open-closed/",children:"Фабричный метод и применение стратегии"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://github.com/torokmark/design_patterns_in_typescript/blob/master/strategy/strategy.ts",children:"Реализация стратегии на TypeScript"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/decorator",children:"Декоратор"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://www.cs.colorado.edu/~kena/classes/5448/f09/lectures/18-decoratorfactory.pdf",children:"Decorator and Factory, Colorado Computer Science, PDF"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://github.com/torokmark/design_patterns_in_typescript/blob/master/decorator/decorator.ts",children:"Реализация декоратора на TypeScript"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://refactoring.guru/ru/design-patterns/observer",children:"Наблюдатель"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://github.com/torokmark/design_patterns_in_typescript/blob/master/observer/observer.ts",children:"Реализация наблюдателя на TypeScript"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://blog.aspiresys.pl/technology/example-of-just-in-time-design-refactor-to-open-closed/",children:"Example of Just-in-time design: refactoring to OCP"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"https://www.goodreads.com/book/show/9850098-essential-skills-for-the-agile-developer?ac=1&from_search=true&qid=9fcKu3LDl6&rank=1",children:"Essential Skills for the Agile Developer, Chapter 11: Refactor to the Open-Closed"})}),"\n"]})]})]})}function MDXContent(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,s.jsx)(MDXLayout,_objectSpread(_objectSpread({},e),{},{children:(0,s.jsx)(_createMdxContent,_objectSpread({},e))}))}},6778:function(e,r,t){"use strict";t.d(r,{x:function(){return S}});var n=t(2777),s=t(2262),o=t(748),i=t(5959),a=t(3553),c=t(7247),l=t(9499);let p=/[\p{Lu}]/u,d=/[\p{Ll}]/u,u=/^[\p{Lu}](?![\p{Lu}])/gu,h=/([\p{Alpha}\p{N}
1_]|$)/u,m=/[_.\- ]+/,f=RegExp("^"+m.source),g=RegExp(m.source+h.source,"gu"),x=RegExp("\\d+"+h.source,"gu"),preserveCamelCase=(e,r,t,n)=>{let s=!1,o=!1,i=!1,a=!1;for(let c=0;c<e.length;c++){let l=e[c];a=!(c>2)||"-"===e[c-3],s&&p.test(l)?(e=e.slice(0,c)+"-"+e.slice(c),s=!1,i=o,o=!0,c++):o&&i&&d.test(l)&&(!a||n)?(e=e.slice(0,c-1)+"-"+e.slice(c-1),i=o,o=!1,s=!0):(s=r(l)===l&&t(l)!==l,i=o,o=t(l)===l&&r(l)!==l)}return e},preserveConsecutiveUppercase=(e,r)=>(u.lastIndex=0,e.replaceAll(u,e=>r(e))),postProcess=(e,r)=>(g.lastIndex=0,x.lastIndex=0,e.replaceAll(x,(t,n,s)=>["_","-"].includes(e.charAt(s+t.length))?t:r(t)).replaceAll(g,(e,t)=>r(t)));var j=t(4851),y=t(7294),v=t(3767),b=t(9521),w=b.ZP.fieldset.withConfig({displayName:"style__Container",componentId:"sc-li9fve-0"})(["margin:0 0 1.5rem 0;padding:0;border:0;button{margin-top:-0.2rem;}"]),C=b.ZP.legend.withConfig({displayName:"style__Heading",componentId:"sc-li9fve-1"})(["padding:0;margin:0 0 0.75rem;font-weight:700;display:block;width:100%;max-width:calc(100vw - 2rem);"]),_=b.ZP.button.withConfig({displayName:"style__Button",componentId:"sc-1rihick-0"})(["border:0;background:",";color:",";border-radius:",";padding:0.6em 1.5em;cursor:pointer;font-size:",";margin:0;&:hover{box-shadow:0 2px 10px ",";}&:active,&:active:hover{box-shadow:none;transform:translateY(1px);}&:disabled{cursor:auto;color:",";}&:disabled:hover{box-shadow:none;}"],function(e){return e.theme.buttonBackground},function(e){return e.theme.buttonColor},function(e){return e.theme.radius},function(e){return e.theme.fontSizeRegular},function(e){return e.theme.decorationColorTetriary},function(e){return e.theme.disabledButtonColor}),k=t(512),P=b.ZP.label.withConfig({displayName:"style__Label",componentId:"sc-1uya17d-0"})(["display:block;user-select:none;cursor:pointer;padding:0.5em 2.2em 0.5em 0.8em;position:relative;border:1px solid ",";border-radius:",";line-height:1.4;max-width:calc(100vw - 2rem);&:hover,&:focus-within{background:",";}&::after{content:' ';display:block;position:absolute;top:0.3em;right:0.3em;}&.selected{border-color:",";}&.completed{cursor:default;&::after{content:'\uD83D\uDEAB';}&.correct::after{content:'✅';}&:hover,&:focus-within{background:none;}}"],function(e){return e.theme.decorationColorPrimary},function(e){return e.theme.radius},function(e){return e.theme.variantHoverBackground},function(e){return e.theme.variantSelectedBorderColor}),O=b.ZP.div.withConfig({displayName:"style__Description",componentId:"sc-1uya17d-1"})(["font-style:italic;color:",";line-height:1.4;padding-top:0.5em;"],function(e){return e.theme.textColorSecondary}),Z=b.ZP.div.withConfig({displayName:"style__Item",componentId:"sc-1uya17d-2"})(["margin:0 0 1rem 0;p:last-child{margin-bottom:0;}"]);b.ZP.div.withConfig({displayName:"style__CodeWrapper",componentId:"sc-1uya17d-3"})(["margin-top:0.5em;pre{margin:0 -1.4rem 0.25em 0;box-shadow:inset 0 0 1px ",";}"],function(e){return e.theme.decorationColorPrimary});var N=t(6168),F=t(5893),R=function(e){(0,i.Z)(Variant,e);var r,t=(r=function(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}(),function(){var e,t=(0,c.Z)(Variant);if(r){var n=(0,c.Z)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,a.Z)(this,e)});function Variant(){var e;(0,n.Z)(this,Variant);for(var r=arguments.length,s=Array(r),i=0;i<r;i++)s[i]=arguments[i];return e=t.call.apply(t,[this].concat(s)),(0,l.Z)((0,o.Z)(e),"handleChange",function(){var r=e.props,t=r.index;(0,r.onToggleAnswer)(t)}),e}return(0,s.Z)(Variant,[{key:"render",value:function(){var e=this.props,r=e.completed,t=e.selected,n=e.correct,s=e.index,o=e.name,i=e.variant,a=i.text,c=i.description;return(0,F.jsxs)(Z,{children:[(0,F.jsxs)(P,{className:(0,k.Z)({selected:t,correct:n,completed:r}),children:[(0,F.jsx)(N.T,{children:(0,F.jsx)("input",{type:"checkbox",name:o,value:s,checked:t,disabled:r,onChange:this.handleChange})}),(0,F.jsx)("div",{children:a})]}),!!c&&r&&(0,F.jsx)(O,{children:c})]})}}]),Variant}(y.PureComponent),T=function(e){(0,i.Z)(BaseQuizContainer,e);var r,t=(r=function(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}(),function(){var e,t=(0,c.Z)(BaseQuizContainer);if(r){var n=(0,c.Z)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,a.Z)(this,e)});function BaseQuizContainer(){var e;(0,n.Z)(this,BaseQuizContainer);for(var r=arguments.length,s=Array(r),i=0;i<r;i++)s[i]=arguments[i];return e=t.call.apply(t,[this].concat(s)),(0,l.Z)((0,o.Z)(e),"toggleAnswer",function(r){e.props.quizModel.toggleAnswer(r)}),e}return(0,s.Z)(BaseQuizContainer,[{key:"render",value:function(){var e=this,r=this.props,t=r.quizModel,n=r.question,s=r.variants,o=r.name;return(0,F.jsxs)(w,{children:[(0,F.jsx)(C,{children:n}),s.map(function(r,n){return(0,F.jsx)(R,{name:o,selected:t.answers.includes(n),completed:t.isComplete,correct:t.isComplete&&t.isCorrect(n),index:n,variant:r,onToggleAnswer:e.toggleAnswer},n)}),(0,F.jsx)(_,{disabled:0===t.answers.length,onClick:function(){return t.toggleComplete()},type:"button",children:t.isComplete?"Пройти заново":"Проверить ответ"})]})}}]),BaseQuizContainer}(y.Component);(0,l.Z)(T,"defaultProps",{completed:!1,variants:[]});var A=(0,j.Pi)(T),D=function(e){(0,i.Z)(QuizLoader,e);var r,t=(r=function(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}(),function(){var e,t=(0,c.Z)(QuizLoader);if(r){var n=(0,c.Z)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,a.Z)(this,e)});function QuizLoader(e){(0,n.Z)(this,QuizLoader),r=t.call(this,e),(0,l.Z)((0,o.Z)(r),"module",void 0),(0,l.Z)((0,o.Z)(r),"moduleName",void 0);var r,s=r.props.name;return r.state={error:null},r.moduleName=function(e,r){if(!("string"==typeof e||Array.isArray(e)))throw TypeError("Expected the input to be `string | string[]`");if(r={pascalCase:!1,preserveConsecutiveUppercase:!1,...r},0===(e=Array.isArray(e)?e.map(e=>e.trim()).filter(e=>e.length).join("-"):e.trim()).length)return"";let t=!1===r.locale?e=>e.toLowerCase():e=>e.toLocaleLowerCase(r.locale),n=!1===r.locale?e=>e.toUpperCase():e=>e.toLocaleUpperCase(r.locale);if(1===e.length)return m.test(e)?"":r.pascalCase?n(e):t(e);let s=e!==t(e);return s&&(e=preserveCamelCase(e,t,n,r.preserveConsecutiveUppercase)),e=e.replace(f,""),e=r.preserveConsecutiveUppercase?preserveConsecutiveUppercase(e,t):t(e),r.pascalCase&&(e=n(e.charAt(0))+e.slice(1)),postProcess(e,n)}(s),r.module=v[r.moduleName],null==r.module&&(r.state={error:"Module ".concat(r.moduleName," not found. Check components/Quiz/quiz-list")}),r}
1return(0,s.Z)(QuizLoader,[{key:"componentDidCatch",value:function(e){console.error(e),this.setState({error:e.message})}},{key:"injected",get:function(){return this.props}},{key:"renderError",value:function(){var e=this.state.error;return(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)("p",{children:"Ошибка загрузки модуля:"}),(0,F.jsx)("pre",{children:e})]})}},{key:"renderQuiz",value:function(){var e=this.injected.app.getByName(this.moduleName);return(0,F.jsx)(A,{name:this.moduleName,quizModel:e,question:this.module.question,variants:this.module.variants})}},{key:"render",value:function(){var e=this.state.error,r=this.injected.app.getByName(this.moduleName);return e?this.renderError():r?this.renderQuiz():null}}]),QuizLoader}(y.Component),S=(0,j.f3)("app")((0,j.Pi)(D))},2042:function(e,r,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/ocp/patterns",function(){return t(7062)}])}},function(e){e.O(0,[374,214,774,888,179],function(){return e(e.s=2042)}),_N_E=e.O()}]);
2//# sourceMappingURL=patterns-8fe941c575e50cb8.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.