JavaScript Паттерны #1 - Singleton (Одиночка)

Поделиться
HTML-код
  • Опубликовано: 7 авг 2019
  • #YauhenK #webDev #JS #JSPatterns
    Всех приветствую в курсе «JavaScript Паттерны».
    В данном видео-курсе мы с вами рассмотрим самые распространённые паттерны проектирования, которые используются при разработке.
    Паттерны, или шаблоны - это определённые, зарекомендовавшие себя конструкции, которые служат для решения типовых задач программирования.
    Рассматривать мы их с вами будем на примере языка JavaScript в синтаксисе ES6.
    ✒ Репозиторий курса:
    ✔ GitHub: github.com/YauhenKavalchuk/de...
    ✒ Используемые ресурсы и инструменты:
    ✔ Carbon (Screenshots): carbon.now.sh/
    ✒ Полезные ссылки:
    ✔ ES6: • ES6
    ✒ Полный список готовых и планируемых курсов:
    ✔ Trello: trello.com/b/R6rD7qq8
    ✒ Автор курса:
    ✔ RUclips: / yauhenkavalchuk
    ✔ Instagram: / yauhenkavalchuk
    ✔ Twitter: / yauhenkavalchuk
    ✔ VK: YauhenKavalchuk
    ✔ LinkedIn: / yauhenkavalchuk
    ✔ GitHub: github.com/YauhenKavalchuk
    ✔ VK (Группа): webdevcom
    ✒ Поддержать развитие канала: github.com/YauhenKavalchuk/yo...

Комментарии • 112

  • @gitarmengitarmenovich767
    @gitarmengitarmenovich767 3 года назад

    @webDev , спасибо за курс, все понятно. Попробовал реализовать этот паттерн на примере корзины, и как-то запутался..., реализовал подключение корзины в родительском компоненте, и в дочерних обращался к нему, но все же если импортировать этот же класс в дочернем и вызвать его конструктор, то он перестает быть синглтоном
    import Basket from './basket'
    class Parent {
    static basket = null
    prepare() {
    this.basket = new Basket()
    }
    }
    class Child extends Parent{
    prepare() {
    super.prepare()
    this.basket.addProduct('item')
    this.basket.getProducts()
    let newInstance = new Basket()
    newInstance.getProducts() //Новый экземпляр
    }
    }
    Код корявые наброски(прошу не критиковать)), но все же, можно как-то сделать чтоб даже при импорте класс в проекте оставался синглтоном, без создания прослойки?

  • @user-vu6hn4ul2i
    @user-vu6hn4ul2i 4 года назад +21

    Некоторые спрашивают, зачем это нужно на практике? Приведу свой пример: есть класс, инкапсулирующий работу с хранилищем firebase. Снаружи он реализует интерфейс типа "дай то", "дай это", "запиши то", "запиши это". Внутре же он инициализирует соединение с базой данных, содержит данные конфигурации и путей, преобразует хотелки в конкретные запросы согласно API. Так вот, не желательно при наличии созданного подключения пытаться создать его заново. Не критично, но и не желательно.
    Вся история происходит в React, сервер могут пинать разные компоненты из разных мест, каждому из них нужна ссылка на экземпляр класса, они его получают через import. Мне хотелось бы гарантировать, что соединение будет инициализированно один раз. Запилил singletone, и не парюсь, один раз прочитает webpack импорты, или не один.

    • @eugenenovikov671
      @eugenenovikov671 2 года назад +1

      это только пишущим на react надо объяснять что такое синглтон, у нас в ангуляре все сервисы синглтоны

    • @Sergey_Klimov
      @Sergey_Klimov 15 дней назад

      ​@@eugenenovikov671да умница, возьми с полки пирожок.

    • @eugenenovikov671
      @eugenenovikov671 15 дней назад

      @@Sergey_Klimov долго думал что бы написать такое?

    • @Sergey_Klimov
      @Sergey_Klimov 15 дней назад

      @@eugenenovikov671 нет. Аналогичный вопрос и тебе, чсвшный ангулярщик

    • @eugenenovikov671
      @eugenenovikov671 15 дней назад

      @@Sergey_Klimov ммм подгорело, понимаю.

  • @yevheniimoskalenko1624
    @yevheniimoskalenko1624 3 года назад +1

    Спасибо, понял только на практике)

  • @flockast
    @flockast 3 года назад

    Спасибо за видео! Подскажите пожалуйста, подобную реализацию модуля можно назвать singleton? Ведь при подключении мы получаем один и тот же instance.
    class Counter {
    constructor () {
    this.count = 0
    }
    ...
    }
    export default new Counter()

  • @valeriyk7565
    @valeriyk7565 5 месяцев назад

    Красава! Спасибо!

  • @sargernax
    @sargernax 4 года назад +3

    Да супер ваще )))

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад

      Спасибо за отзыв!

    • @sargernax
      @sargernax 4 года назад

      @@YauhenKavalchuk К сожалению пока нет денег, с удовольствием заплатил бы вам за уроки.

  • @lizzienovigot
    @lizzienovigot 4 года назад +1

    Спасибо. Не задумывался что можно так сделать хоть и знал про такое поведение конструктора существует. Всегда удивлялся зачем такое правило)))

  • @rusnickk
    @rusnickk 4 года назад +3

    Спасибо за видео, к 3:30 вопрос каждый новый вызов конструктора будет сбрасывать счётчик, думаю инициализация count должна быть в ветке if и отрабатывать ровно один раз если !instance?

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад

      В целом да, можно и так сделать.

  • @Daddar2253
    @Daddar2253 3 года назад

    подскажите, так как мы используем new для получения синглтона, то по идее каждый раз, когда мы ходим взять созданный инстанс, мы все равно выделяем память для создания пустого Counter (хоть и в конструкторе подменяем на инстанс). ок ли это?
    в теории можно создать статичный метод у класса (или функцию с замыканием), тогда такой проблемы не будет

  • @jocoders6175
    @jocoders6175 4 года назад

    Красавелла!

  • @dmitrykorovin4356
    @dmitrykorovin4356 3 года назад

    доходчиво, спасибо за видео

  • @andriidou8023
    @andriidou8023 4 года назад +2

    код в RunJS вроде написан, класная вещь если хочется что-то затестить в js а разворачивать среду лень, туда даже либы можно импортить, Крч всем советую поставить и попробовать

    • @mustapha_mond
      @mustapha_mond 4 года назад

      спасибо за комментарий, дельная штука!

  • @everdimension
    @everdimension 4 года назад +5

    Спасибо за видео и старания. Но даже оставив вопрос о том, где этот паттерн может быть полезен, скажу, что вот такие видео в контексте js порождают только больше непонимания относительно паттернов проектирования. В js нет никакого смысла создавать синглтон описанным в видео способом. ES-модули являются синглтонами сами по себе. Достаточно создать файл и экспортировать желаемый объект или методы. Вот и весь "синглтон". А трюки со статическим полем instance нужны только в джаве.

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад

      И тем не менее, Singleton- это отдельный паттерн, который вполне резонно попал в этот курс. Но на счёт модулей, абсолютно согласен

    • @everdimension
      @everdimension 4 года назад +3

      ​@@YauhenKavalchuk Я согласен, что паттерн не стоит обходить стороной. Проблема на мой взгляд в том, что почти во всех материалах, рассказывающих об этих паттернах, за кадром остаётся главное - мотивация. Когда именно они уместны. Но реальные примеры никто не приводит. Лишь абстрактные советы (бездушное "адаптер полезен, когда вам нужно использовать имеющийся класс для клиента, ожидающего другой интерфейс") или с головой погружения в "заводы для бмв".

    • @alehmakaranka1089
      @alehmakaranka1089 4 года назад

      Блин, точняк

  • @user-se2zt4oh3i
    @user-se2zt4oh3i Год назад

    Спасибо, всё наглядно и понятно

  • @pcaptanovsky
    @pcaptanovsky 6 месяцев назад +1

    проблема такой реализации, что свойство instance никак не защищено, и если после создания первого экземпляра класса и перед созданием второго присвоить null свойству Counter.instance, то второй экземпляр получит ссылку на пустой объект.
    а можно и другой объект туда передать, со своими свойствами и переписанными методами, которые при вызове будут делать уже совсем не то, что мы планировали.

  • @freedom_twin
    @freedom_twin 4 года назад +12

    instance.count = 0 наверное должен быть в блоке if, иначе он каждый раз будет обнулять счетчик?(3:22)

    • @user-vu6hn4ul2i
      @user-vu6hn4ul2i 4 года назад +3

      Полез в комменты написать это. А тут ты )).

    • @mitrasu5918
      @mitrasu5918 2 года назад

      @@user-vu6hn4ul2i я такаяже хуйня

  • @irynabelaya8191
    @irynabelaya8191 3 года назад +2

    Про синглтон: а как это будет реализваться в объекте, на основе созданного класса? То есть в новом объект будет свойство instance (или что это будет?)? И каким образом нам ссылаться из нового объекта на функцию-конструктор? И зачем нам может понадобиться ссылаться на функцию -конструктор?

    • @Sergey_Klimov
      @Sergey_Klimov 15 дней назад

      Никто не ответит, потому что привыкли все только общие случаи объяснять. Как дело доходит до тонкостей, то в лучшем случае на стаковерфлоу найдешь ответ. И то даже там поглумятся над вопросом, потому что не хотят показывать, что сами ничего не знают

  • @JenechekDv
    @JenechekDv 4 года назад

    Когда на собеседовании спрашиваю про паттерны лучше начинать с чего то другого)

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад

      Почему?)

    • @JenechekDv
      @JenechekDv 4 года назад

      @@YauhenKavalchuk Начинающие часто учат этот паттерн первым и на собеседовании сразу выдают его т.к. он один из самых простых. Сам так делал и более опытные коллеги говорят, что если человек начинает с одиночки, велика вероятность, что он только его и знает и надо уделить этой теме больше внимания.

  • @user-cx1di5zg9m
    @user-cx1di5zg9m Год назад

    Спасибо, объяснили четко и ясно, я правильно понял, синглтон - это что-то в единственном экземпляре, я люблю аналогию, и можно ли синглотн сравнить с рулем от автомобиля? Руль - является синглотоном, но при этом на него могут влиять другие части, допустим: рулевая рейка, поворот колес, без использования руля и т.п. Т.е синглтон это что-то единственное в своем роде. Допустим есть список песен, я делаю запрос, получаю музыку, слушаю ее, переключаю и тд - это всё объекты и данные, а вот плеер, который есть на моей странице - это синглтон, правильно ли рассуждаю?

    • @YauhenKavalchuk
      @YauhenKavalchuk  Год назад +1

      Вроде как рассуждения верны

  • @qazyhn94
    @qazyhn94 4 года назад +2

    вопрос такой, если мы используем require или import модули из ES6, вот этот самый require читает файл один раз во время жизни программы, тоесть если мы делаем export default new Singleton() в файле модуля, всегда когда я буду делать import в коде я получу один и тот же обьект, что по сути и есть синглтон благодаря модулям, есть ли какие то минусы у такого подхода?

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад +1

      Нет. Просто это не нативная реализация, а реализация с помощью сборщика

    • @lizzienovigot
      @lizzienovigot 4 года назад +1

      Мне кажется это лучше реализация. Описанная в видео плоха тем что пользователь может создавать "разные" экземпляры не понимая что они есть один и тот же обьект. Это может легко привести к багам.

    • @user-vu6hn4ul2i
      @user-vu6hn4ul2i 4 года назад

      Разница в том, что require или import это инструкции сборщика, а не часть языка JS (пока, во всяком случае). А он читает один раз, но НЕ ГАРАНТИРУЕТ, что чтение будет произведено ровно один раз. В принципе, из каких-либо своих соображений, он может прочитать пару раз. Или завтра реализацию переделают. Ставить свой код в зависимость от таких факторов - не лучшая идея.

  • @NewDimix
    @NewDimix 2 месяца назад

    Не понял с каких пор и по каким причинам синглтон стал антипаттерном? Вот это интересно было бы послушать

  • @user-ns4js5wl5n
    @user-ns4js5wl5n 4 года назад +2

    спасибо за видео, но я так и не понял ( + запутался ) примерное назначение етого паттерна... если объекты разные (false) то ето потому что они совсем 2 чужих объекта, если надо сделать (true) то надо сохранить силку объекта в другой переменой и сравнивать, и не надо юзать конструкцию класса и методов

    • @s_bandera
      @s_bandera 4 года назад +2

      Говорить научись, потом вопросы формулировать, а потом вопрошай.

  • @gtdsafafasf
    @gtdsafafasf 4 года назад +2

    По сути в JS если просто объявить переменную в глобальной области, скажем: let counter = 0; и просто обращаться к ней из разных точек программы то это уже singleton ? Зачем мы вообще используем класс Counter для реализации этого паттерна ? Что бы снабдить доступ к переменной instance внешним удобным интерфейсом ? Есть ли еще причины, по которым мы используем класс ?

    • @user-vu6hn4ul2i
      @user-vu6hn4ul2i 4 года назад

      Это для примера. Не обязательно же там одна переменная. Воспринимай переменную как массив нужного и полезного кода, инкапсулированного в отдельный класс.

    • @andrewklochko340
      @andrewklochko340 2 года назад

      А если понадобится создать ограничение, допустим счётчик не должен быть меньше нуля? Если переменная будет глобальная, её можно вертеть как хотеть. Работая через методы можно сделать проверку, а в случае неверных значений предпринять какие-то действия (вернуть ошибку, предупреждение, поставить дэфолтное значение)

  • @pupizoid100
    @pupizoid100 Год назад

    А через сингл паттерн можно реализовать функцию, чтоб на одной странице проигрывалось только одно видео с ютуба из всех остальных?

  • @Fodintsov
    @Fodintsov 2 года назад +3

    Можно просто создать класс со static-методами и static-переменными. Тоже синглтон. :)

  • @dezo103
    @dezo103 4 года назад +4

    Спасибо за курс, но мне как новичку не понятно)))

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад +3

      Вам, как новичку, я бы не рекомендовал лезть в этот курс. И для начала подтянуть основы

    • @user-oz6xm9zp9d
      @user-oz6xm9zp9d 10 месяцев назад

      я с небольшим опытом , и то думаю применить не применить и забываю что то и лезу тоже в такие курсы и мне тоже не сразу понятно =))))) один раз пока я применял синглтон

  • @arman-6172
    @arman-6172 Год назад

    Голова бобо с такого =)
    $counter1 = new Counter();
    $counter2 = new Counter();
    $counter1 === $counter2 // true
    Кроме JS где-то еще можно так? Как-то больше через статику видел. Может это нюанс JS и не стоит на нем пример паттерна показывать? или это общая практика в JS? Тут я больше про реализацию паттерна в конструкторе.

  • @codeforgames
    @codeforgames Год назад

    Я все же пришел к проверке такого типа:
    if (Singleton.instance instanceof Singleton) return Singleton.instance;
    Более правильная, на мой взгляд)
    Если короче, то вообще if (Singleton.instance ) return Singleton.instance;

  • @Sergey_Klimov
    @Sergey_Klimov 15 дней назад

    Тогда непонятно зачем создавать новый экземпляр класса к каждой переменной. Ну был бы это export default обычный и все.

  • @nun8930
    @nun8930 4 года назад

    Автор у меня вопрос, стоит ли лезть во фронтенд без знания математики?
    Я правда залез немножко уже, и теперь возник этот вопрос, и не знаю, тратить ли свое время дальше.

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад +1

      Стоит, всё нормально

    • @eugenegavrilov2618
      @eugenegavrilov2618 4 года назад +4

      за несколько лет работы, только месяца 2 назад, первый раз понадобилась математика и геометрия

    • @nun8930
      @nun8930 4 года назад

      Благодарю за ответы

    • @user-jw9hg6xj9k
      @user-jw9hg6xj9k 4 года назад

      Программирование намного больше похоже на физику чем на математику

  • @dmitriifisenko6069
    @dmitriifisenko6069 2 года назад

    них...я не понял но очень интересно!

  • @zerdox4
    @zerdox4 4 года назад

    почему ты говоришь что instance - глобальная переменная, если в джаваскрипте глобальные переменные это свойства глобального объекта?

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад

      Прочитайте по терминологии JS и всё поймёте

  • @_kie
    @_kie 4 года назад +1

    Так у класса или у объекта - в определении этого паттерна именно объект? Потому что начал ты с объекта, а закончил классом. Решил посмотреть еще какую-нибудь статью по теме, открыл Медиум, там тоже начинается с объекта, потом, внезапно, идёт про класс. WTF?

    • @raptorthefirst
      @raptorthefirst 4 года назад

      Так что тебе мешает переписать это под объект ?

    • @raptorthefirst
      @raptorthefirst 4 года назад

      Ну тип function Singleton() {..}
      Почти ничего не меняется. Когда вызываешь конструктор через new, то тип можно просто прописать в начале условие, что если объект существует, ссылаться на него. Изи

    • @raptorthefirst
      @raptorthefirst 4 года назад

      let instance;
      -class Singleton{
      - constructor(){
      - if(!instance) instance = this;
      +function Singleton(){
      +
      + if(!instance) instance = this;
      + else{
      instance.count = 0;
      return instance;
      }
      -
      - showCount(){
      +
      + this.showCount = function(){
      console.log(instance.count);
      }
      - increaseCount(){
      + this.increaseCount = function(){
      return instance.count++;
      }
      }
      +
      let car1 = new Singleton;
      let car2 = new Singleton;
      git push youtube Лови )))

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад +8

      Под капотом, классы в JS являются объектами. Классов в «классическом» смысле не существует.

  • @BrainProletarian
    @BrainProletarian 3 года назад

    4:53 "Мы сохранили ссылку на экземпляр в статическом свойстве конструктора" - не правильнее было сказать "Сохранили ссылку на экземпляр в статическом свойстве нашего класса-функции", т.к. по тексту возникает двусмысленность из-за наличии в классе функции "constructor"?

  • @deadhead7303
    @deadhead7303 5 месяцев назад

    Явно ошибка в конструкторе, если инстанс не существует, то необходимо в условие взять все условия, а не только присвоение текущего контекста.

  • @nataliashiryaeva5259
    @nataliashiryaeva5259 4 года назад

    зачем глобальная переменная и при чем здесь синтаксис ES6? Это же статическое свойство вы добавляете (без ключевого слова). И зачем проверка на object?
    Вот такая конструкция решает проблему во всех синтаксисах:
    if (!Count.instance) Count.instance = this;
    else return Count.instance;
    подход тот же - если объект уже существует, то не создавай новый, а верни старый.
    (И возвращать this не нужно, конструкторы это неявно делают.)
    я не придираюсь :) Просто не вижу слабые места в указанной мной конструкции

    • @user-vu6hn4ul2i
      @user-vu6hn4ul2i 4 года назад

      Else не нужен. Так как ты написала, мы проверяем, существует ли instance, и если да, то возвращаем его. Если же нет, то создаём его и полагаемся на возврат конструктором this.
      Если же написать всё то же самое, но без else, то мы будем проверять, есть ли instance, если нет, то создавать его, и всегда возвращать instance. Разницы, вроде, нет особо. Что приходит на ум, а может ли this при каких нибудь условиях != instance? Понятно, что не в данном примере.

  • @RK-gm4pd
    @RK-gm4pd 4 года назад

    WTF вопросов больше, чем полученного материала!
    "обьект, которий есть в одном єкземпляре" - обьект, как обьект ООП, не JS object literal, потому как последний по определению в одном єкземпляре, потому как реферальний тип. И об єтом в видео сказано. Зачем переписивать { obj } в Class что би потом через instance получить доступ к свойствам и методам, которие уже есть в obj _proto_ ? Зачем создавать два "разних" instance, чтоби потом обратиться к тому же свойству того же обьекта?
    "и к которому может бить доступ из разних частей программи". вот тут вобще не понял! если ми создаем глобальную переменную, то как к ней не может бить достпа? И отсюда опять вопрос: "Глобальная переменная єто хорошо нам, или плохо?" Модульная система предотвращает доступ к глобальним переменним извне приложения, а необходимость глобальних переменних диктуется архитектурой приложения. Значит ли єто, что Синглтон вместе с ООП идут лесом?
    в ES модульной системе нельзя импортировать и мутировать переменую саму по себе:
    // ES module Singlton.js
    export let Global = 0;
    // app.js
    import { Global } from 'Singlton.js' ;
    console.log(Global); // 0
    Global = Global++; // TypeError: can't assign to 'Global' because it's not a variable or Assignment to constant variable.
    потому как модуль/файл заворачивается в IIFE (тоже упомянуто в видео), и потому: Синглтон от ООП - снова в сад! А по природе JS на сегодня - "синглтон"для глобальной переменной не минуем на корню:
    // ES module Singlton.js
    let Global = 0;
    export const increaseGlobal = () => {
    Global++;
    }
    export const getGlobal = () => {
    return Global;
    }
    // app.js
    import { getGlobal, increaseGlobal } from 'Singlton.js';
    let Global = getGlobal();
    console.log(Global); // 0
    increaseGlobal();
    Global = getGlobal();
    console.log(Global); // 1
    increaseGlobal();
    Global = getGlobal();
    console.log(Global); // 2
    ...

  • @glucus2274
    @glucus2274 Год назад

    Иными словами Store == Singleton

  • @user-rj6ro3mp1p
    @user-rj6ro3mp1p 4 года назад

    градиент привлекает внимание больше чем код на темном фоне. Глаз начинает дергаться от напряжения, ну, это у меня так, по крайней мере.

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад

      Такой стиль будет во всех уроках, заделать ничего не могу, т.к. весь материал уже отснят

    • @user-rj6ro3mp1p
      @user-rj6ro3mp1p 4 года назад +4

      @@YauhenKavalchuk, ладно, будем монитор скотчем обклеивать тогда по периметру🤣

  • @oOIMAXIOo
    @oOIMAXIOo 4 года назад +2

    Не совсем понял зачем он нужен, если корзину можно просто запихнуть в localstorage и иметь доступ кней с любой страницы?

    • @qazyhn94
      @qazyhn94 4 года назад +1

      А если мы пишем на Node? ))

    • @andriidou8023
      @andriidou8023 4 года назад

      1. LocalStorage не для этого придуман
      2. В некоторых браузерах в режиме инкогнито недоступен localStorage соответственно апка будет не рабочая
      3. А если у тебя будет 10 -15 синглтонов ты будешь их все на старте через JSON.stringify() перегонять и писать в localStorage а затем через JSON.parse() доставать. Звучит тупо согласись.

    • @YauhenKavalchuk
      @YauhenKavalchuk  4 года назад +1

      Это хороший вариант, а если такую имплементацию делать не получается. Паттерны - это просто шаблоны. Если вы не понимаете зачем тот, или иной паттерн, то скорее всего он вам просто не нужен, пока...)

    • @oOIMAXIOo
      @oOIMAXIOo 4 года назад

      @@andriidou8023 Искренне надеюсь ты нескем не общаешься с людьми кроме как со мной! Манера общения у тебя как высокомерного дегенерата, тебя бы закрыть в комнате со своими фотками и своим кодом...

    • @oOIMAXIOo
      @oOIMAXIOo 4 года назад

      @@YauhenKavalchuk Да я уверен просто не сталкивался еще с таким родом проблем, поэтому и спросил когда и зачем он нужен!)

  • @user-el3hb3uo5e
    @user-el3hb3uo5e 3 месяца назад

    Насколько я понял это похоже на vuex, pinia, redux и тд

  • @O_Hat
    @O_Hat Год назад +1

    Я понял, сначала нужно ставить дизлайк, па потом лайк

  • @s_bandera
    @s_bandera 4 года назад

    Да уж, сейчас бы паттерны на js учить в 2к19....