Как мой аргумент относительно глобальных объектов в пространстве имен против синглетонов? - PullRequest
2 голосов
/ 02 ноября 2010

Мой коллега хочет использовать одноэлементный паттерн в javascript для ссылки на объекты, которые в нашем текущем приложении могут быть созданы только один раз.

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

Его аргумент заключается в том, что если когда-либо будет разрешено создавать более одного из этих объектов, стоимость рефакторинга будетниже при использовании синглетонов, потому что меньше кода придется менять.

Например, допустим, у нас есть приложение с большим центральным элементом интерфейса, например карта в Google Maps.

Я обычно хочу получить доступ к карте из кода приложения, например:

Application.interface.map.zoom(10);

Он хочет получить доступ к карте по всему коду приложения, например:

var map = new Map(); // This is invisibly a singleton
map.zoom(10);

ДляНапример, код в классе ButtonsControl, представляющий кнопки, управляющие картой, должен был бы каким-либо образом получить доступ к карте, чтобы отразить ввод пользователя.Если он получит доступ к карте, используя new или Application?

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

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

Например, при чтении кода в ButtonsControl вы можете быть испуганы, увидев, что, по-видимому, new Map()будучи созданным в вашем конструкторе ButtonsControl, вы должны будете изучить код Map, чтобы убедиться, что это на самом деле не происходит.Либо выследить это, либо уже знать, что new Map() является единичным, - это то, что требует затрат при использовании new Map(), тогда как чтение Application.interface.Map очевидно и не обременяет будущего читателя кода.

Даже если синтаксис new Map() будет изменен на Map.get_instance(), мой аргумент состоял в том, что использование синглтона на самом деле приведет к дальнейшей работе позже, если мы решим когда-нибудь разрешить несколько карт, потому что код, написанный вокруг синглтона, будет фактически вести себя какхотя важно, чтобы он работал на конкретной карте, а не, возможно, создавал новую карту и работал с it .Другими словами, мне интересно, хороший ли тест для того, использовать ли одиночный код или нет, если код, окружающий его, кажется независимым от того, работает ли он над реальным новым объектом или существующим объектом.Например, канонический пример подключения к базе данных проходит этот тест.

Я знаю, что это не так много информации, но ... хорошо, поэтому создание стандартов кодирования является трудным делом;Трудно принимать эти решения без точной информации.Но предположим, что вы разрабатывали Карты Google с нуля сегодня, и вам пришлось принять это решение.Я также знаю, что это смехотворно маленький вопрос, но по какой-то причине я интуитивно сильно предпочитаю свою версию и пытаюсь понять, почему.

Что вы выбираете и почему?

Ответы [ 3 ]

3 голосов
/ 02 ноября 2010

Я бы сказал, что оба метода хуже.Я согласен с вашими чувствами по поводу того, что «new» сбивает с толку, но «Application.interface.map», помимо того, что он слишком многословен, является гарантированным кошмаром рефакторинга в будущем.передайте «большой переменный» в качестве параметра тому, кто в нем нуждается, и заблокируйте его в замыкании.

 function initButton(map) {
    someButton.onclick = function() { map.zoom() }
 }

Пока вы используете одну карту, ваша «основная» функция может быть замыканиема также.

(function(map) {

     // init things here

}) ( someInstanceOfMap )

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

2 голосов
/ 02 ноября 2010

Что касается дизайна, синтаксис не имеет значения. Если фрагмент кода предполагает, что существует только одна карта, то этот фрагмент кода необходимо будет переписать в тот день, когда ваше приложение должно использовать две карты. Независимо от того, приняло ли это предположение форму «карта получена с Application.interface.map» или «карта получена с new Map», не имеет никакого значения.

Я согласен, что более подходящее имя класса будет new MapRef или new MapProxy, потому что вы создаете новую ссылку на существующую карту, а не на новую карту. Это снимет усталость любого читателя и позволит получить код на том же уровне хрупкости, что и синглтон (потому что, опять же, вы создаете прокси, а не карты, поэтому сначала должна быть карта для прокси) Но кроме этого, оба решения эквивалентны с точки зрения дизайна.

Чистый способ спроектировать это - предоставить карту в качестве аргумента всем функциям, которые над ней работают (либо напрямую, либо как член объекта, доступного для этой функции). Даже если у вас никогда не было более одной карты в любой момент времени на вашей странице, вы все равно можете запустить модульные тесты (которые могут включать создание mock карт).

Для справки, предложение вашего коллеги известно как шаблон Monostate , который в основном эквивалентен Singleton с точки зрения воздействия на дизайн.

1 голос
/ 02 ноября 2010

Идея вашего коллеги безумна.Скрывать синглтон внутри конструктора - это ядовитая, ужасная вещь.

Что еще более важно, вы совершенно правы, когда говорите:

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

И, как вы боитесь, пока у вас действительно есть синглтон, однакоон реализован, вы будете писать так, как будто у вас есть синглтон.

С другой стороны, звучит так, как будто есть большой шанс, что у вас будет только один синглтон.В этом случае применяется YAGNI, и вы должны сделать самое простое, что могло бы сработать сейчас, и подумать о том, как это исправить, если это когда-нибудь случится, что вам нужно.

...