2012-05-18 2 views
8

Вот сценарий. Как создатель публично лицензированных API с открытым исходным кодом, моя группа создала платформу пользовательского интерфейса на основе Java (так что же еще нового?). Чтобы все было хорошо и организовано так, как нужно на Java, мы использовали пакеты с соглашением об именах org.mygroup.myframework.x, причем x - это такие вещи, как компоненты, валидаторы, конвертеры, утилиты и т. Д. (Опять же, что еще новый?).Недопустимый модификатор доступа «уровень рамки»

Теперь, где-то в классе org.mygroup.myframework.foo.Bar есть метод void doStuff(), что мне нужно выполнить логику, специфичную для моей структуры, и мне нужно иметь возможность называть ее из нескольких других мест в моей структуре , например, org.mygroup.myframework.far.Boo. Учитывая, что Boo не является ни подклассом Bar, ни в том же пакете, метод doStuff() должен быть объявлен общедоступным, чтобы быть вызванным Boo.

Однако мои рамки существуют как инструмент, позволяющий другим разработчикам создавать более простые и элегантные R.I.A.s для своих клиентов. Но если com.yourcompany.yourapplication.YourComponent называет doStuff(), это может иметь неожиданные и нежелательные последствия. Я бы предпочел, чтобы этого никогда не было позволено. Обратите внимание, что в Bar содержатся другие методы, которые действительно общедоступны.

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

[org.mygroup.myframework.*] void doStuff() { .... } 

где подстановочные будет означать любой класс, пакет начинается с org.mygroup.myframework может позвонить, но никто другой.

Учитывая, что этого мира не существует, какие еще хорошие варианты у нас есть?


Обратите внимание, что это мотивировано реальным сценарием; имена были изменены для защиты виновных. Существует реальная основа, в которой на всем протяжении своего Javadoc можно найти общие методы, которые комментируются как «ЭТОТ МЕТОД ВНУТРЕННЕГО ДЛЯ MYFRAMEWORK И НЕ ЧАСТЬ ЕГО ПУБЛИЧНОГО API. НЕ ЗВОНИТЕ !!!!!!» Небольшое исследование показывает, что эти методы вызываются из других источников в рамках.

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


Update: Не обижайтесь к двум отвечающими до сих пор, но я думаю, что вы промахнулись, или я не выразить это хорошо. В любом случае, я могу попытаться осветить вещи. Постарайтесь, как я могу, как разработчикам фреймворка было реорганизовано следующее. Обратите внимание, что это очень грубый пример.

package org.mygroup.myframework.foo; 
public class Bar { 
    /** Adds a Bar component to application UI */ 
    public boolean addComponentHTML() { 
     // Code that adds the HTML for a Bar component to a UI screen 
     // returns true if successful 
     // I need users of my framework to be able to call this method, so 
     // they can actually add a Bar component to their application's UI 
    } 

    /** Not really public, do not call */ 
    public void doStuff() { 
     // Code that performs internal logic to my framework 
     // If other users call it, Really Bad Things could happen! 
     // But I need it to be public so org.mygroup.myframework.far.Boo can call 
    } 
} 

Еще одно обновление: Я только что узнал, что C# имеет "внутренний" модификатор доступа. Поэтому, возможно, лучший способ сформулировать этот вопрос мог бы быть следующим: «Как имитировать/эмулировать внутренний доступ в Java?» Тем не менее, я не ищу новых ответов.Наш босс в конечном итоге согласился с упомянутыми выше проблемами

+0

Звучит как отличный случай для разделения вашего публичного API и реализации на отдельные проекты с публичным API, состоящим из большого количества интерфейсов. – Perception

+0

@Перцепция: Я считаю, что это то, что делает JSF, с отдельными jsf-api.jar и jsf-impl.jar. – cobaltduck

+1

'Существует реальная структура, в которой на всем протяжении своего Javadoc можно найти общедоступные методы, прокомментированные как ...« Хм, мне интересно, какая структура может быть :)) – biziclop

ответ

0

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

Конечно, даже если у вас есть мелкие разрешенные разрешения, вы все равно не сможете предотвратить вызов клиентским модулем внутренних методов --- jvm не защищает от вызовов, основанных на отражении, для частных методов так или иначе.

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

До тех пор, пока вы убедитесь, что во время выполнения загружается только одна реализация для каждого документационного интерфейса, современный jvm гарантирует, что вы не получите никакого штрафа за его использование; и вы можете загружать версии жгута/заглушки во время тестирования для дополнительного бонуса.

0

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

+0

Пожалуйста, определите «CDI» – cobaltduck

+0

Я не знаю ничего о CDI, в частности, но я бы предположил, что shuuchan ссылается на контексты и инжекцию зависимостей: http://jcp.org/en/jsr/detail?id = 299 – Curtis

0

Нет поддержки в языке Java для такого уровня доступа (вы хотели бы что-то вроде «внутреннего» с пространством имен). Вы можете ограничить доступ только к уровню пакета (или к известной модели наследования, защищенной частной защитой).

Из моего опыта вы можете использовать соглашение Eclipse: создать пакет под названием «внутренний», чтобы вся иерархия классов (включая подпакеты) этого пакета считалась не-API-кодом и могла быть изменена в любое время без гарантия для ваших пользователей. В этом коде, отличном от API, используйте общедоступные методы, когда захотите. Поскольку это только соглашение, и оно не применяется компилятором JVM или Java, вы не можете запретить пользователям использовать этот код, но, по крайней мере, пусть знают, что эти классы не предназначены для использования третьими лицами.

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

+0

Моя проблема в том, что класс, который я назвал org.mygroup.myframework.foo.Bar, содержит как общедоступный метод, который я хочу, чтобы другие приложения могли звонить, так и тот, который у меня нет. – cobaltduck

0

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

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

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

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