Для чего нужны пространства имен? как насчет использования? - PullRequest
7 голосов
/ 01 сентября 2010
  1. для чего предназначены пространства имен?

  2. и, что более важно, должны ли они использоваться как объекты в Java (вещи, которые имеют данные и функции и которые пытаются достичь инкапсуляции)? эта идея надуманна? :)

  3. или они должны использоваться в качестве пакетов в Java?

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

Ответы [ 4 ]

9 голосов
/ 01 сентября 2010

Учитывая, что вы используете тег Clojure, я предполагаю, что вас заинтересует специфичный для Clojure ответ:

какова цель пространства имен?

Пространства имен Clojure, пакеты Java, модули Haskell / Python / любые другие ... На очень высоком уровне это все разные имена для одного и того же базового механизма, основной целью которого является предотвращение столкновений имен в нетривиальных кодовых базах. Конечно, у каждого решения есть свои маленькие изюминки, которые имеют смысл в контексте данного языка и не имеют смысла вне его. Остальная часть этого ответа будет касаться завихрений и причуд, характерных для Clojure.

Группы пространств имен Clojure Vars , которые являются контейнерами, содержащими функции (чаще всего), макро-функции (функции, используемые компилятором для генерации макроразложений соответствующих форм, обычно определяемых с помощью defmacro; на самом деле они просто обычные функции Clojure, хотя есть некоторая магия в том, как они регистрируются компилятором) и иногда различные «глобальные параметры» (скажем, clojure.core/*in* для стандартного ввода), Atoms / Refs и т. д. Средство протокола, введенное в Clojure 1.2 обладает хорошим свойством, что протоколы поддерживаются Vars, как и отдельные функции протокола; это ключ к тому, как протоколы представляют решение проблемы выражения (что, вероятно, выходит за рамки этого ответа!).

Разумеется, пространства имен должны группировать переменные, которые так или иначе связаны между собой. В общем, создание пространства имен - это быстрая и дешевая операция, поэтому совершенно нормально (и действительно обычно) использовать одно пространство имен на ранних стадиях разработки, а затем, когда появляются независимые блоки функциональности, выделять их в свои собственные пространства имен, промыть и повторить ... Только вещи, которые являются частью общедоступного API, должны быть распределены между пространствами имен заранее (или, скорее: до стабильного выпуска), поскольку тот факт, что такая-то функция находится в пространстве имен, и так, конечно, является частью API.

и, что более важно, должны ли они использоваться как объекты в Java (вещи, которые имеют данные и функции и которые пытаются достичь инкапсуляции)? эта идея надуманна? :)

Обычно ответ - нет. Вы можете получить изображение не слишком далеко от истины, если подходите к ним как к классам со множеством статических методов, без методов экземпляра, без открытых конструкторов и часто без состояния (хотя иногда могут быть некоторые «члены данных класса» в форме Vars с атомами / ссылками); но, возможно, было бы более полезно не пытаться применять метафоры Java-ish к идиомам Clojure и подходить к пространству имен как к группе функций и т. д., а не к «классу, содержащему группу функций» или к чему-то подобному.

Существует важное исключение из этого общего правила: пространства имен, включающие :gen-class в их ns форме. Они предназначены именно для реализации Java-класса, который позже может быть создан, который может иметь методы экземпляра и состояние для каждого экземпляра и т. Д. Обратите внимание, что :gen-class является функцией взаимодействия - чистый код Clojure, как правило, должен этого избегать.

или они должны использоваться как пакеты в java?

Они служат для тех же целей, для которых предназначены пакеты (как уже упоминалось выше); аналогия, хотя она и есть, не очень полезна, просто потому, что вещи, которые пакеты группируют (классы Java), совсем не похожи на вещи, которые пространства имен Clojure группируют (Clojure Vars), различные «уровни доступа» (private / package / public в Java, {:private true} или нет в Clojure) работают совсем иначе и т. Д.

При этом нужно помнить, что существует определенное соответствие между пространствами имен и пакетами / классами, находящимися в определенных пакетах.Пространство имен с именем foo.bar при компиляции создает класс с именем bar в пакете foo;это означает, в частности, что имена пространств имен должны содержать хотя бы одну точку, так как так называемые односегментные имена, очевидно, приводят к тому, что классы помещаются в «пакет по умолчанию», что приводит к всевозможным странностям.(Например, я считаю невозможным, чтобы профилировщик VisualVM замечал какие-либо функции, определенные в односегментных пространствах имен.)

Кроме того, deftype / defrecord созданные типы не находятся в пространствах имен ,Форма (defrecord Foo [...] ...) в файле, где определено пространство имен foo.bar, создает класс с именем Foo в пакете foo.bar.Чтобы использовать тип Foo из другого пространства имен, нужно было бы :import класс Foo из пакета foo.bar - :use / :require не будет работать, так как они извлекают Vars из пространств имен,какие записи / типы не являются.

Таким образом, в данном конкретном случае существует определенное соответствие между пространствами имен и пакетами, о котором должны знать программисты Clojure, которые хотят воспользоваться некоторыми из новых возможностей языка.Некоторые считают, что это дает «вкус взаимодействия» к функциям, которые иначе не считаются принадлежащими к сфере взаимодействия (defrecord / deftype / defprotocol - хороший механизм абстракции, даже если мы забываем об их роли в достижениискорость платформы на JVM), и вполне возможно, что в некоторых будущих версиях Clojure этот вариант может быть устранен, так что соответствие имени пространства имен / имени пакета для deftype & Co. может рассматриваться как деталь реализации.

или они должны использоваться более широко как модульная система или как-то еще?

Они являются модульной системой, и это действительно так, как они должныиспользоваться.

2 голосов
/ 01 сентября 2010

Пакет в Java имеет свое собственное пространство имен, которое обеспечивает логическую группировку классов.Это также помогает предотвратить конфликты имен.Например, в Java вы найдете java.util.Date и java.sql.Date - два разных класса с одинаковыми именами, различающимися по пространству имен.Если вы попытаетесь импортировать оба файла в java-файл, вы увидите, что он не будет компилироваться.По крайней мере, одна версия должна будет использовать свое явное пространство имен.

1 голос
/ 01 сентября 2010

С независимой от языка точки зрения пространства имен - это способ изолировать вещи (то есть инкапсулировать в смысле). Это более общая концепция (см., Например, пространства имен XML). Вы можете «создавать» пространства имен несколькими способами, в зависимости от языка, который вы используете: пакеты, статические классы, модули и так далее. Все это обеспечивает пространства имен для объектов / данных / функций, которые они содержат. Это позволяет лучше организовать код, изолировать функции, улучшить повторное использование кода и адаптивность (как инкапсуляция) Как сказано в «Zen of Python», «Пространства имен - это одна из замечательных идей - давайте сделаем больше!».

0 голосов
/ 01 сентября 2010

Думайте о них как о контейнерах для ваших занятий. Например, если у вас есть вспомогательный класс для построения строк, и вы хотите использовать его на своем бизнес-уровне, вы бы использовали пространство имен, например MyApp.Business.Helpers. Это позволяет вашим классам содержаться в чувственных местах, поэтому, когда вы или кто-то еще, ссылаясь на свой код, хотите посчитать их, они могут быть легко найдены. В другом примере, если вы хотите использовать вспомогательный класс SQL-соединения, вы, вероятно, будете использовать что-то вроде:

MyApp.Data.SqlConnectionHelper sqlHelper = new MyApp.Data.SqlConnectionHelper();

На самом деле вы бы использовали оператор "using", чтобы вам не нужно было полностью определять пространство имен только для объявления переменной.

Пол

...