Является ли класс «мастер предпочтений» хорошей идеей? - PullRequest
8 голосов
/ 27 февраля 2009

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

В ходе этого я столкнулся с еще одним следствием дизайна централизации. Программное обеспечение имеет публичный API. Этот API может быть предоставлен сам по себе в банке. Классы в этом API могут ссылаться на класс управления pref. Итак, преф менеджер должен идти в API jar.

Каждое предпочтение может иметь значение по умолчанию. При запуске программного обеспечения это значение по умолчанию может быть вычислено. Алгоритм зависит от предпочтения и, следовательно, имеет тенденцию находиться рядом с кодом использования. Так что, если преф менеджер должен установить значение по умолчанию, он вызывает соответствующий класс.

Но теперь, когда pref manager стал «классом осьминога», он засасывает всевозможные классы в jar API, которого там быть не должно. Если этого не произойдет, программы, использующие jar API, быстро столкнутся с исключениями ClassDef. Если это так, то API jar теперь раздут, поскольку каждый из этих других классов может ссылаться на другие.

В целом, другие программисты на Java управляют своими предпочтениями с помощью централизованного класса?

Имеет ли смысл распространять этот статический класс управления pref как часть публичного API?

Должен ли этот преф-менеджер быть хранителем кода для определения значений по умолчанию?

Ответы [ 6 ]

11 голосов
/ 27 февраля 2009

ИМХО, я думаю, что ответ на ваш первый вопрос - «да» и «нет».

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

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

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

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

Если вы используете одну функцию API для получения «справочного менеджера», вы можете предоставить пользователям возможность предоставить свой собственный «калькулятор значений по умолчанию». Менеджер предпочтений сначала спросит этот калькулятор, прежде чем прибегнуть к тому, который вы предоставили по умолчанию.

4 голосов
/ 27 февраля 2009

Разве вы не можете просто обработать предпочтения в действительно общем виде? Затем вы просто используете диспетчер предпочтений для обработки постоянства. Таким образом, из класса вы бы просто сказали менеджеру предпочтений PreferenceManager.setPreference (ключ, значение), и ему все равно, что он сохраняет, с точки зрения семантики данных.

Или я слишком упрощаю это?

2 голосов
/ 27 февраля 2009

Я не Java Dev, но что касается всего "класса осьминога", можете ли вы не просто предоставить интерфейс для jar и соединить вызовы между интерфейсом и менеджером prefs во время выполнения, используя приложение файл конфигурации для определения менеджера prefs для создания экземпляра?

Что-то вроде шаблона провайдера .NET?

Таким образом, вы можете отделить свою банку от менеджера prefs.

1 голос
/ 27 февраля 2009

Возможно, вы захотите взглянуть на класс NSUserDefaults Какао для вдохновения. Он решает проблему, которую вы описываете, имея несколько уровней предпочтений, называемых доменами. Когда вы ищите значение для ключа, например «PrintUsingAllCaps», оно сначала проверяет значение в локальном домене пользователя. Если его там нет, он может проверить системный домен или домен сетевого уровня и т. Д.

Абсолютное последнее место, которое он проверяет, называется «Домен регистрации», в котором, как правило, должны присутствовать жестко заданные значения по умолчанию. Таким образом, в любой точке моего кода я могу записать предпочтение в домен регистрации, и NSUserDefaults будет обслуживать это значение, только если пользователь не переопределил его.

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

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

0 голосов
/ 05 февраля 2010

API JSR-10 (java.util.prefs.*) использует фабричный метод с параметром Class<?> для создания Preferences экземпляров. Таким образом, API может хранить настройки из разных классов, принадлежащих к одному и тому же пакету, в одном файле.

0 голосов
/ 02 марта 2009

Я удалил свой первый ответ, так как неправильно понял, о чем спрашивал автор.

Чтобы на самом деле ответить на реальный вопрос - кажется, что ваше желание разместить предпочтения (и вычисление значений по умолчанию) с кодом, который их использует, имеет смысл.

Не могли бы вы удовлетворить оба требования, используя класс контейнера предпочтений для каждой области, которая следует шаблону для этой области, но зарегистрировав его в «Глобальной» коллекции объектов предпочтений?

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

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

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

Это похоже на работу некоторых регистраторов. Существует центральный механизм для поддержки уровней журналов, потоков вывода и тому подобного, но у каждого класса есть свой экземпляр метода «log» и он регистрирует его.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...