Могу ли я предоставить интерфейс, позволяющий другому классу разрешить мне доступ к его закрытым переменным? - PullRequest
1 голос
/ 05 декабря 2011

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

Я пишу класс, который предназначен для расширения.Проблемная область - глобальная оптимизация, поэтому любой программист конечного пользователя, который подклассирует мой класс (я буду называть их Стивом), будет предоставлять свою собственную проблему и алгоритм ее решения;Я просто предоставляю фреймворк (сеть, пользовательский интерфейс и т. Д.).Программа Стива может потребовать любое количество настроек конфигурации;Я хочу, чтобы мой код мог получать эти настройки от пользователя так же, как он получает свои собственные настройки (будь то из панели управления с графическим интерфейсом пользователя, файла конфигурации XML или чего-либо еще).Стиву не нужно дублировать какой-либо мой код, а также он не должен нарушать тип безопасности Java или модель инкапсуляции.

В идеале Стив мог бы написать что-то вроде этого:

public class SteveClass extends MyFrameworkClass {

    @Configurable
    private int foo;

    @Configurable
    private String bar;

    private boolean baz;

    // implementations of my abstract methods, etc.

}

Configurable - это предоставленная мной аннотация, которая указывает, что аннотированная переменная является параметром конфигурации, который я должен получить от пользователя.Как вы можете видеть, я также хочу, чтобы Стив мог объявлять другие переменные экземпляра для своего собственного внутреннего использования, которых я никогда не трогал.

Я собирался реализовать это, включив в MyFrameworkClass метод, который быпереберите getClass().getDeclaredFields() и определите поля с аннотациями Configurable.Затем он записывает пользовательский ввод в эти поля.Это не обязательно должно выглядеть точно так, с аннотациями и прочим, но вы поймете идею.

Проблема с этим, конечно, в том, что foo и bar являются частными и кодируются вMyFrameworkClass не может написать им, даже задумчиво.Не помогло бы, если бы они были закрытыми для пакета, поскольку код Стива не будет в том же пакете, что и мой, и я бы предпочел, чтобы он не делал их общедоступными или добавлял какой-либо другой интерфейс, который позволял бы кому-либо, кромемне получить доступ к полям.

Есть ли способ сделать то, что я хочу, либо возиться с SecurityManager, либо сделать что-то совершенно другое?

Ответы [ 3 ]

2 голосов
/ 05 декабря 2011

Если бы я был на вашем месте, я бы попытался найти способ использовать среду Spring, чтобы сделать это для меня.Это позволит пользователям написать следующее:

@Component
public class SteveClass {
    @Value("${steve.foo}")
    private int foo;

    @Value("${steve.bar}")
    private String bar;

    private boolean baz;

    @Autowired(required = false)
    private DaveClass dave;
}

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

1 голос
/ 05 декабря 2011

Вы можете использовать Class.getDeclaredFields, чтобы получить все объявленные поля класса (включая непубличные), а затем Field.setAccessible(true), чтобы получить к нему доступ.

Field foo = HasPrivate.class.getDeclaredField("foo");
foo.setAccessible(true);
SteveClass steve = new SteveClass();
System.out.println(steve); // "0" -- I set up SteveClass.toString() to just print foo
foo.setInt(hp, 1234);
System.out.println(steve); // "1234"

Но это означает, что вы 'в зависимости от SecurityManager, чтобы позволить вам сделать это.Это происходит по умолчанию, но это может работать не для всех пользователей.Если это непомерное требование, существуют другие, менее удобные, но потенциально более надежные параметры (например, требование, чтобы конструктор взял объект конфигурации, из которого пользователь затем может получить значения).

0 голосов
/ 05 декабря 2011
  1. Создание интерфейса конфигурации

    interface Configuration
    {
        int foo ( ) ;
    
        String bar ( ) ;
    }
    
  2. Использование интерфейса конфигурации

    public class SteveClass extends MyFrameworkClass {
        private Configuration configuration ;
    
        // implementations of my abstract methods, etc.
    
    }
    

Я думаю, это называется делегированием.

...