[
  {
    "path": ".gitignore",
    "content": ".idea\n"
  },
  {
    "path": "1 creational/1_constructor.js",
    "content": "// function Server(name, ip) {\n//   this.name = name\n//   this.ip = ip\n// }\n//\n// Server.prototype.getUrl = function() {\n//   return `https://${this.ip}:80`\n// }\n\nclass Server {\n  constructor(name, ip) {\n    this.name = name\n    this.ip = ip\n  }\n\n  getUrl() {\n    return `https://${this.ip}:80`\n  }\n}\n\nconst aws = new Server('AWS German', '82.21.21.32')\nconsole.log(aws.getUrl())\n"
  },
  {
    "path": "1 creational/2_factory.js",
    "content": "class SimpleMembership {\n  constructor(name) {\n    this.name = name\n    this.cost = 50\n  }\n}\n\nclass StandardMembership {\n  constructor(name) {\n    this.name = name\n    this.cost = 150\n  }\n}\n\nclass PremiumMembership {\n  constructor(name) {\n    this.name = name\n    this.cost = 500\n  }\n}\n\nclass MemberFactory {\n  static list = {\n    simple: SimpleMembership,\n    standard: StandardMembership,\n    premium: PremiumMembership\n  }\n\n  create(name, type = 'simple') {\n    const Membership = MemberFactory.list[type] || MemberFactory.list.simple\n    const member = new Membership(name)\n    member.type = type\n    member.define = function() {\n      console.log(`${this.name} (${this.type}): ${this.cost}`)\n    }\n    return member\n  }\n}\n\nconst factory = new MemberFactory()\n\nconst members = [\n  factory.create('Vladilen', 'simple'),\n  factory.create('Elena', 'premium'),\n  factory.create('Vasilisa', 'standard'),\n  factory.create('Ivan', 'premium'),\n  factory.create('Petr')\n]\n\nmembers.forEach(m => {\n  m.define()\n})\n"
  },
  {
    "path": "1 creational/3_prototype.js",
    "content": "const car = {\n  wheels: 4,\n\n  init() {\n    console.log(`У меня есть ${this.wheels} колеса, мой владелец ${this.owner}`)\n  }\n}\n\nconst carWithOwner = Object.create(car, {\n  owner: {\n    value: 'Дмитрий'\n  }\n})\n\nconsole.log(carWithOwner.__proto__ === car)\n\ncarWithOwner.init()\n"
  },
  {
    "path": "1 creational/4_singleton.js",
    "content": "class Database {\n  constructor(data) {\n    if (Database.exists) {\n      return Database.instance\n    }\n    Database.instance = this\n    Database.exists = true\n    this.data = data\n  }\n\n  getData() {\n    return this.data\n  }\n}\n\nconst mongo = new Database('MongoDB')\nconsole.log(mongo.getData())\n\nconst mysql = new Database('MySQL')\nconsole.log(mysql.getData())\n\n\n"
  },
  {
    "path": "2 structural/5_adapter.js",
    "content": "class OldCalc {\n  operations(t1, t2, operation) {\n    switch (operation) {\n      case 'add': return t1 + t2\n      case 'sub': return t1 - t2\n      default: return NaN\n    }\n  }\n}\n\nclass NewCalc {\n  add(t1, t2) {\n    return t1 + t2\n  }\n\n  sub(t1, t2) {\n    return t1 - t2\n  }\n}\n\nclass CalcAdapter {\n  constructor() {\n    this.calc = new NewCalc()\n  }\n\n  operations(t1, t2, operation) {\n    switch (operation) {\n      case 'add': return this.calc.add(t1, t2)\n      case 'sub': return this.calc.sub(t1, t2)\n      default: return NaN\n    }\n  }\n}\n\nconst oldCalc = new OldCalc()\nconsole.log(oldCalc.operations(10, 5, 'add'))\n\nconst newCalc = new NewCalc()\nconsole.log(newCalc.add(10, 5))\n\nconst adapter = new CalcAdapter()\nconsole.log(adapter.operations(25, 10, 'sub'))\n\n\n"
  },
  {
    "path": "2 structural/6_decorator.js",
    "content": "class Server {\n  constructor(ip, port) {\n    this.ip = ip\n    this.port = port\n  }\n\n  get url() {\n    return `https://${this.ip}:${this.port}`\n  }\n}\n\nfunction aws(server) {\n  server.isAWS = true\n  server.awsInfo = function() {\n    return server.url\n  }\n  return server\n}\n\nfunction azure(server) {\n  server.isAzure = true\n  server.port += 500\n  return server\n}\n\nconst s1 = aws(new Server('12.34.56.78', 8080))\nconsole.log(s1.isAWS)\nconsole.log(s1.awsInfo())\n\nconst s2 = azure(new Server('98.87.76.12', 1000))\nconsole.log(s2.isAzure)\nconsole.log(s2.url)\n"
  },
  {
    "path": "2 structural/7_facade.js",
    "content": "class Complaints {\n  constructor() {\n    this.complaints = []\n  }\n\n  reply(complaint) {}\n\n  add(complaint) {\n    this.complaints.push(complaint)\n    return this.reply(complaint)\n  }\n}\n\nclass ProductComplaints extends Complaints {\n  reply({id, customer, details}) {\n    return `Product: ${id}: ${customer} (${details})`\n  }\n}\n\nclass ServiceComplaints extends Complaints {\n  reply({id, customer, details}) {\n    return `Service: ${id}: ${customer} (${details})`\n  }\n}\n\nclass ComplaintRegistry {\n  register(customer, type, details) {\n    const id = Date.now()\n    let complaint\n\n    if (type === 'service') {\n      complaint = new ServiceComplaints()\n    } else {\n      complaint = new ProductComplaints()\n    }\n\n    return complaint.add({id, customer, details})\n  }\n}\n\nconst registry = new ComplaintRegistry()\n\nconsole.log(registry.register('Vladilen', 'service', 'недоступен'))\nconsole.log(registry.register('Elena', 'product', 'вылазит ошибка'))\n\n"
  },
  {
    "path": "2 structural/8_flyweight.js",
    "content": "class Car {\n  constructor(model, price) {\n    this.model = model\n    this.price = price\n  }\n}\n\nclass CarFactory {\n  constructor() {\n    this.cars = []\n  }\n\n  create(model, price) {\n    const candidate = this.getCar(model)\n    if (candidate) {\n      return candidate\n    }\n\n    const newCar = new Car(model, price)\n    this.cars.push(newCar)\n    return newCar\n  }\n\n  getCar(model) {\n    return this.cars.find(car => car.model === model)\n  }\n}\n\nconst factory = new CarFactory()\n\nconst bmwX6 = factory.create('bmw', 10000)\nconst audi = factory.create('audi', 12000)\nconst bmwX3 = factory.create('bmw', 8000)\n\nconsole.log(bmwX3 === bmwX6)\n\n"
  },
  {
    "path": "2 structural/9_proxy.js",
    "content": "function networkFetch(url) {\n  return `${url} - Ответ с сервера`\n}\n\nconst cache = new Set()\nconst proxiedFetch = new Proxy(networkFetch, {\n  apply(target, thisArg, args) {\n    const url = args[0]\n    if (cache.has(url)) {\n      return `${url} - Ответ из кэша`\n    } else {\n      cache.add(url)\n      return Reflect.apply(target, thisArg, args)\n    }\n  }\n})\n\nconsole.log(proxiedFetch('angular.io'))\nconsole.log(proxiedFetch('react.io'))\nconsole.log(proxiedFetch('angular.io'))\n"
  },
  {
    "path": "3 behaviour/10_chain_of_responsibility.js",
    "content": "class MySum {\n  constructor(initialValue = 42) {\n    this.sum = initialValue\n  }\n\n  add(value) {\n    this.sum += value\n    return this\n  }\n}\n\nconst sum1 = new MySum()\nconsole.log(sum1.add(8).add(10).add(1).add(9).sum)\n\nconst sum2 = new MySum(0)\nconsole.log(sum2.add(1).add(2).add(3).sum)\n"
  },
  {
    "path": "3 behaviour/11_comand.js",
    "content": "class MyMath {\n  constructor(initialValue = 0) {\n    this.num = initialValue\n  }\n\n  square() {\n    return this.num ** 2\n  }\n\n  cube() {\n    return this.num ** 3\n  }\n}\n\nclass Command {\n  constructor(subject) {\n    this.subject = subject\n    this.commandsExecuted = []\n  }\n\n  execute(command) {\n    this.commandsExecuted.push(command)\n    return this.subject[command]()\n  }\n}\n\nconst x = new Command(new MyMath(2))\n\nconsole.log(x.execute('square'))\nconsole.log(x.execute('cube'))\n\nconsole.log(x.commandsExecuted)\n\n"
  },
  {
    "path": "3 behaviour/12_iterator.js",
    "content": "class MyIterator {\n  constructor(data) {\n    this.index = 0\n    this.data = data\n  }\n\n  [Symbol.iterator]() {\n    return {\n      next: () => {\n        if (this.index < this.data.length) {\n          return {\n            value: this.data[this.index++],\n            done: false\n          }\n        } else {\n          this.index = 0\n          return {\n            done: true,\n            value: void 0\n          }\n        }\n      }\n    }\n  }\n}\n\nfunction* generator(collection) {\n  let index = 0\n\n  while (index < collection.length) {\n    yield collection[index++]\n  }\n}\n\n\nconst iterator = new MyIterator(['This', 'is', 'iterator'])\nconst gen = generator(['This', 'is', 'iterator'])\n\n// for (const val of gen) {\n//   console.log('Value: ', val)\n// }\n\nconsole.log(gen.next().value)\nconsole.log(gen.next().value)\nconsole.log(gen.next().value)\n\n\n"
  },
  {
    "path": "3 behaviour/13_mediator.js",
    "content": "class User {\n  constructor(name) {\n    this.name = name\n    this.room = null\n  }\n\n  send(message, to) {\n    this.room.send(message, this, to)\n  }\n\n  receive(message, from) {\n    console.log(`${from.name} => ${this.name}: ${message}`)\n  }\n}\n\nclass ChatRoom {\n  constructor() {\n    this.users = {}\n  }\n\n  register(user) {\n    this.users[user.name] = user\n    user.room = this\n  }\n\n  send(message, from, to) {\n    if (to) {\n      to.receive(message, from)\n    } else {\n      Object.keys(this.users).forEach(key => {\n        if (this.users[key] !== from) {\n          this.users[key].receive(message, from)\n        }\n      })\n    }\n  }\n}\n\nconst vlad = new User('Vladilen')\nconst lena = new User('Elena')\nconst igor = new User('Igor')\n\nconst room = new ChatRoom()\n\nroom.register(vlad)\nroom.register(lena)\nroom.register(igor)\n\nvlad.send('Hello!', lena)\nlena.send('Hello hello!', vlad)\nigor.send('Vsem privet')\n"
  },
  {
    "path": "3 behaviour/14_observer.js",
    "content": "class Subject {\n  constructor() {\n    this.observers = []\n  }\n\n  subscribe(observer) {\n    this.observers.push(observer)\n  }\n\n  unsubscribe(observer) {\n    this.observers = this.observers.filter(obs => obs !== observer)\n  }\n\n  fire(action) {\n    this.observers.forEach(observer => {\n      observer.update(action)\n    })\n  }\n}\n\nclass Observer {\n  constructor(state = 1) {\n    this.state = state\n    this.initialState = state\n  }\n\n  update(action) {\n    switch (action.type) {\n      case 'INCREMENT':\n        this.state = ++this.state\n        break\n      case 'DECREMENT':\n        this.state = --this.state\n        break\n      case 'ADD':\n        this.state += action.payload\n        break\n      default:\n        this.state = this.initialState\n    }\n  }\n}\n\nconst stream$ = new Subject()\n\nconst obs1 = new Observer()\nconst obs2 = new Observer(42)\n\nstream$.subscribe(obs1)\nstream$.subscribe(obs2)\n\nstream$.fire({type: 'INCREMENT'})\nstream$.fire({type: 'INCREMENT'})\nstream$.fire({type: 'DECREMENT'})\nstream$.fire({type: 'ADD', payload: 10})\n\nconsole.log(obs1.state)\nconsole.log(obs2.state)\n"
  },
  {
    "path": "3 behaviour/15_state.js",
    "content": "class Light {\n  constructor(light) {\n    this.light = light\n  }\n}\n\nclass RedLight extends Light {\n  constructor() {\n    super('red')\n  }\n\n  sign() {\n    return 'СТОП'\n  }\n}\n\nclass YellowLight extends Light {\n  constructor() {\n    super('yellow')\n  }\n\n  sign() {\n    return 'ГОТОВЬСЯ'\n  }\n}\n\nclass GreenLight extends Light {\n  constructor() {\n    super('green')\n  }\n\n  sign() {\n    return 'ЕДЬ!'\n  }\n}\n\nclass TrafficLight {\n  constructor() {\n    this.states = [\n      new RedLight(),\n      new YellowLight(),\n      new GreenLight()\n    ]\n    this.current = this.states[0]\n  }\n\n  change() {\n    const total = this.states.length\n    let index = this.states.findIndex(light => light === this.current)\n\n    if (index + 1 < total) {\n      this.current = this.states[index + 1]\n    } else {\n      this.current = this.states[0]\n    }\n  }\n\n  sign() {\n    return this.current.sign()\n  }\n}\n\nconst traffic = new TrafficLight()\nconsole.log(traffic.sign())\ntraffic.change()\n\nconsole.log(traffic.sign())\ntraffic.change()\n\nconsole.log(traffic.sign())\ntraffic.change()\n\nconsole.log(traffic.sign())\ntraffic.change()\n\nconsole.log(traffic.sign())\ntraffic.change()\n\nconsole.log(traffic.sign())\ntraffic.change()\n"
  },
  {
    "path": "3 behaviour/16_strategy.js",
    "content": "class Vehicle {\n  travelTime() {\n    return this.timeTaken\n  }\n}\n\nclass Bus extends Vehicle {\n  constructor() {\n    super()\n    this.timeTaken = 10\n  }\n}\n\nclass Taxi extends Vehicle {\n  constructor() {\n    super()\n    this.timeTaken = 5\n  }\n}\n\nclass Car extends Vehicle {\n  constructor() {\n    super()\n    this.timeTaken = 3\n  }\n}\n\nclass Commute {\n  travel(transport) {\n    return transport.travelTime()\n  }\n}\n\nconst commute = new Commute()\n\nconsole.log(commute.travel(new Taxi()))\nconsole.log(commute.travel(new Bus()))\nconsole.log(commute.travel(new Car()))\n"
  },
  {
    "path": "3 behaviour/17_template.js",
    "content": "class Employee {\n  constructor(name, salary) {\n    this.name = name\n    this.salary = salary\n  }\n\n  responsibilities() {}\n\n  work() {\n    return `${this.name} выполняет ${this.responsibilities()}`\n  }\n\n  getPaid() {\n    return `${this.name} имеет ЗП ${this.salary}`\n  }\n}\n\nclass Developer extends Employee {\n  constructor(name, salary) {\n    super(name, salary)\n  }\n\n  responsibilities() {\n    return 'процесс создания программ'\n  }\n}\n\nclass Tester extends Employee {\n  constructor(name, salary) {\n    super(name, salary)\n  }\n\n  responsibilities() {\n    return 'процесс тестирования'\n  }\n}\n\nconst dev = new Developer('Владилен', 100000)\nconsole.log(dev.getPaid())\nconsole.log(dev.work())\n\nconst tester = new Tester('Виктория', 90000)\nconsole.log(tester.getPaid())\nconsole.log(tester.work())\n"
  }
]