Есть ли способ сделать переменные класса A модифицируемыми только классами определенного интерфейса?

Class A {
   String x;
}

У меня есть 2 интерфейса I1 и I2.

Класс C1 реализует I1

Класс C2 реализует I2

Есть ли способ разрешить только классу C2 обновлять x класса A? то есть есть ли способ, с помощью которого классы, реализующие конкретный интерфейс, обновляют членов класса A?

Классы, реализующие I1, должны иметь возможность читать только членов класса A, и им не должно быть разрешено обновлять члены класса A.


person myst    schedule 12.11.2019    source источник
comment
Было бы интересно узнать процесс проектирования, который привел к этой необходимости.   -  person Federico klez Culloca    schedule 12.11.2019
comment
Отвечает ли это на ваш вопрос? Java: как ограничить доступ к определенному классу?   -  person Guy    schedule 12.11.2019
comment
Я сомневаюсь, что вы действительно хотите это сделать. Это звучит как основная проблема дизайна.   -  person Marcel    schedule 12.11.2019
comment
@Federico Я создаю платформу, состоящую из нескольких независимых компонентов. Ему нужны классы, реализующие определенный интерфейс, только для обновления списка глобальных переменных, а другие классы не должны иметь возможности его изменять.   -  person myst    schedule 12.11.2019


Ответы (3)


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

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

  2. Попробуйте отделить ограничение авторизации от фактического объекта. Возможно использовать Proxy pattern.

  3. Используйте StackTraceElement для идентификации вызывающего класса/метода. Может быть получено с помощью Thread.currentThread().getStackTrace(). Это также защищает ваш код от обмана метода установки, передавая экземпляр авторизованного класса.

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

person CuriousMind    schedule 12.11.2019
comment
Есть ли недостатки использования Thread.currentThread().getStackTrace() или throwable.getStackTrace()? - person myst; 13.11.2019
comment
Пока недостатков не вижу. Но было бы уместно использовать ThreadStack Trace, а не Throwable stacktrace. Хотя оба они приводят к одному и тому же объекту, исключение вводит ненужный шаблонный код и просто не кажется правильным. Еще одно предупреждение: если ваш код допускает расширение (нет возможности введения перехватчиков или вещей, подобных AspectJ), вам, возможно, придется пройтись по всему стеку, в противном случае достаточно просто обратиться к самому верхнему элементу. - person CuriousMind; 13.11.2019

Хотя это кажется ошибкой дизайна, но вы все равно можете добиться этого, используя instanceof в setter и getter в x:

class A {
    private String x;

    public void setX(String value, Object obj){
        if(obj instanceof I2){
            this.x = value;
        }
    }

    public String getX(Object obj){
        if(obj instanceof I2){
            return this.x;
        }else{
            return null;
        }
    }
}

ИСПОЛЬЗОВАНИЕ:

A a = new A();
a.setX("ABC",this);
a.getX(this);
person Mustahsan    schedule 12.11.2019
comment
Что мешает любому другому объекту создать экземпляр I2 и передать его в A? - person jaco0646; 12.11.2019

Для независимого интерфейса есть только одно решение:

class A {
    private String x;

    public void setX(AUser u, String x) {
        if (u != null) { this.x = x; }
    }
}

interface AUser {
}
person Joop Eggen    schedule 12.11.2019
comment
Это потребует явной передачи интерфейса в аргумент функции - person myst; 12.11.2019
comment
@myst В интерфейсе default setX(A a, String x) {...} будет такая же проблема. Только если А создаст реализацию интерфейса/а, между двумя объектами будет какая-то ссылка, которую можно использовать. - person Joop Eggen; 12.11.2019