2016-10-20 2 views
5

Например, взгляните на мой простой реализации стека:Использует закрытие для эмуляции инкапсуляции плохая идея?

var MyStack = (function() { 
    var min; 
    var head; 

    // Constructor 
    function MyStack() { 
     this.size = 0; 
    } 

    MyStack.prototype.push = function(val) { 
     var node = new Node(val); 

     if (typeof min === 'undefined' || val < min) { 
      min = val; 
     } 

     ++this.size; 
     if (typeof head === 'undefined') { 
      head = node; 
     } else { 
      node.next = head; 
      head = node; 
     } 
    }; 

    MyStack.prototype.pop = function() { 
     if (typeof head === 'undefined') { 
      throw new Error('Empty stack'); 
     } 

     --this.size; 

     var data = head.data; 
     head = head.next; 

     return data; 
    }; 

    MyStack.prototype.min = function() { 
     if (typeof min === 'undefined') { 
      throw new Error('Min not defined'); 
     } 

     return min; 
    }; 

    MyStack.prototype.peek = function() { 
     if (typeof head === 'undefined') { 
      throw new Error('Empty stack'); 
     } 

     return head.data; 
    }; 

    function Node(data) { 
     this.data = data; 
     this.next; 
    } 

    return MyStack; 
})(); 

Используя этот метод, я могу убедиться, что никто не может (случайно или намеренно) манипулировать «частные» поля, такие как мин и головы. Я также могу использовать частные функции, такие как Node(), которые не нужно раскрывать.

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

Я попытался оптимизировать его, используя прототипы вместо создания функций каждый раз, когда создается новый объект. Другими словами, я не включил функции как часть конструктора MyStack.

Мой вопрос в том, что этот плохой дизайн? Существуют ли какие-либо серьезные препятствия для этой методологии?

+1

«Эмулировать инкапсуляцию», возможно, вы имеете в виду «инкапсулирование»? Потому что я не вижу, каким образом это не инкапсуляция. – ruakh

ответ

3

Используется ли закрытие для эмуляции инкапсуляции плохая идея?

Нет. Хотя я не считаю, что это «соревнование», закрытие осуществляют инкапсуляцию.

Я попытался оптимизировать его, используя прототипы вместо создания функций каждый раз, когда создается новый объект. Другими словами, я не включил функции как часть конструктора MyStack.

Мой вопрос в том, что этот плохой дизайн? Существуют ли какие-либо серьезные препятствия для этой методологии?

Да, это на самом деле неправильно. Ваши min и headMyStack и Node) переменными являются по существу статические. Они определяются только один раз и будут использоваться всеми экземплярами. Вы не можете создать два разных стека, они оба будут иметь одинаковую ссылку head.

Чтобы инкапсулировать состояние каждого экземпляра, вам необходимо объявить переменные в конструкторе, чтобы они были созданы с каждым новым объектом. Для этого вам также нужно будет объявить все методы, которые должны получить к ним доступ («привилегированные») в области конструктора.

var MyStack = (function() { 
    function MyStack() { 
     var size = 0; 
     var head = undefined; 

     function checkNonEmpty() { 
      if (typeof head === 'undefined') { 
       throw new Error('Empty stack'); 
      } 
     } 
     this.push = function(val) { 
      size++; 
      head = new Node(val, head); 
     }; 
     this.pop = function() { 
      checkNonEmpty(); 
      this.size--; 
      var data = head.data; 
      head = head.next; 
      return data; 
     }; 
     this.peek = function() { 
      checkNonEmpty(); 
      return head.data; 
     }; 
     this.getSize = function() { 
      return size; 
     }; 
    } 

    function Node(data, next) { 
     this.data = data; 
     this.next = next; 
    } 

    return MyStack; 
})(); 

Если вы хотите поставить эти методы на прототипе, вам нужно будет сделать head и size значения доступны в качестве свойств экземпляра.

+0

О, вау, я не знал, что на самом деле создаю статические поля. Неудивительно, что я сталкивался с некоторыми проблемами при использовании моей реализации. Теперь, когда вы отредактировали мой код, это имеет для меня гораздо больше смысла. По существу, следующая дилемма? Либо имеют «частные» поля, но воссоздают методы каждый раз, когда создается новый объект, или выставляют поля, но пользуются преимуществами памяти прототипа? – gjvatsalya

+0

@gjvatsalya Да, точно. Хотя создание методов на самом деле довольно дешево, вам обычно не нужно беспокоиться об этом. – Bergi

+0

Фантастический, это здорово услышать. Спасибо, что указал на критическую ошибку, которую я сделал. – gjvatsalya

1

Учитывая, что инкапсуляция является одним из принципов объектно-ориентированного программирования, я не думаю, что это плохая практика кодирования. Закрытие в JavaScript - это ваши средства инкапсуляции переменных и ограничение доступа к другим частям приложения.

Во многих отношениях в JavaScript нет ничего надежного. Даже с закрытием, те переменные, которые вы хотите сохранить конфиденциальными, доступны различными способами в разных браузерах. Например, в Google Chrome вы можете установить точку останова в отладчике и получить доступ к любой переменной в активном корпусе. Хотя мы можем сделать многое в браузере для обеспечения безопасности, мы по-прежнему имеем дело с интерпретируемым языком, который скомпилирован на машине, на которой запущен код.

А учитывая ваш пример: var MyStack = (function(){...})(); Если вы когда-нибудь работать с машинописью или какими-либо быстрыми механизмами развития, вы увидите, что это метод вывода кодирования используется для объектов пространства имен, когда рамка компиляции/transpile.

+0

Я вижу, это имеет смысл. Что касается использования отладчика, это означает, что они будут иметь доступ только для чтения, верно? Или они все еще смогут изменить значение, установив точку останова? – gjvatsalya

+0

Кроме того, не могли бы вы объяснить, что вы имели в виду в своем последнем абзаце? Вы просто говорите, что эти рамки используют тот же шаблон, что и тот, который я использовал в моем примере? – gjvatsalya

+0

@gjvatsalya Они могут изменять что-либо в отладчике. Когда вы остановились в точке останова, вы можете дважды щелкнуть по любой из переменных в поле «Область», и это позволит вам ввести новое значение для него. – Barmar

Смежные вопросы