Задать вопрос

Как ограничить вызов метода владельцем объекта?

Добрый день! Я пишу небольшой фреймворк на Java, основанный на акторной модели и обеспечивающий простое взаимодействие потоков.

У меня возникла необычная проблема! Мне нужно чтобы некоторый метод объекта мог быть вызван только из его объекта-контейнера.

Суть вот в чем: у меня есть объект Event (событие). На событие, с помощью метода subscribe() могут подписываться другие персонажи (потоки), когда событие возникает, все эти персонажи получают об этом уведомление. Т.е. метод subscribe() должен быть открыт для всех персонажей программы (для всех потоков). С этим проблем нет — это решает модификатор public.
В свою очередь, метод Event.addReaction() добавляет к событию реакцию, которая должна быть незамедлительно выполнена персонажем-владельцем события. Доступ к этому методу должен иметь только владелец события, т.к. нельзя чтобы персонажи реагировали на чужие события никак иначе кроме после получения сообщения.

Вот кусок утрированного кода:

class Person
{
   Event mItDone = new Event();

   public Person()
   {
       mItDone.subscribe(AnotherPerson);       //AnotherPerson получит сообщение при наступлении события

       mItDone.addReaction(new myReaction());    //myReaction будет выполнено сразу при наступлении события
   }

   private void eventOccurs()
   {
       mItDone.fire();                //Запускает событие (fire не должен быть доступен ни для кого кроме этого экземпляра Person
   }

   class myReaction extends Reaction
   {
      react()
      {
           //Реакция этого персонажа на событие mIdDone;
      }
   }
}


Вот и получается, что мне для правильного функционирования объекта класса Event нужно чтобы методы addReaction() и fire() были доступны только для того объекта, в котором он содержится. Помог бы какой-нибудь специальный модификатор доступа, но таких нет(

Есть мысли?
  • Вопрос задан
  • 4451 просмотр
Подписаться 4 Оценить Комментировать
Решения вопроса 1
@mayorovp
Вариант первый — минимальная защита от индуса:
class Event {
  public void subscribe(...) {}
}

class OwnedEvent extends Event {
  public void fire(...) {}
  public void addReaction(...) {}
}

Владелец события создает объект класса OwnedEvent, но перед передачей его другим объектам приводит к Event. При попытке приведения события обратно — больно бить по рукам.

Вариант второй — максимальная защита от индуса, но с повышенным расходом памяти.
class Event {
  public void subscribe(...) {}

  public static class Owner {
    private final Event event = new Event();

    public void fire(...) {}
    public void addReaction(...) {}

    public Event getEvent() { return event; }
  }
}

Смысл в том, что при таком подходе класс Event.Owner должен иметь доступ к приватным полям класса Event, чем и можно воспользоваться.

PS на Java не писал ничего уже 4 года, могу накосячить с синтаксисом. Надеюсь, это не помешает пониманию написанного.
Ответ написан
Пригласить эксперта
Ответы на вопрос 5
sigod
@sigod
Если я верно понял, вы не хотите чтобы другие объекты могли вызвать mItDone.addReaction() у Person? Тогда почему не пометить mItDone как private, а в Person сделать интерфейс, для сторонних объектов, для подписки?
Ответ написан
Tully
@Tully
Мне кажется тут некоторое смешение понятий. Модификаторы private/public нужны в момент написания кода, для того чтобы проверить что программисты правильно понимают задачи.
В рантайме они не нужны. Пометить как-то в момент написания классов инстансы этих классов при помощи ключевых слов нельзя.
Если нужно отличать инстансы Person друг от друга (например, чтобы один отреагировал на событие, а остальные нет) заведи в этом классе поле с уникальным идентификатором и проверяй в рантайме права доступа на их основе.
Ответ написан
PoN
@PoN
Game Developer, Full-stack developer.
сделайте интерфейс Event, с методами addReaction(),fire(), далее делаете классы наследуемые от Person и реализующие интерфейс Event. Получается классы реализуюшие Event будут иметь эти методы а те кто нет — нет. если правильно понял. Также посмотрите паттерн Observer.
Ответ написан
sigod
@sigod
(ответ был удален)
Ответ написан
Комментировать
@relgames
Java Developer
Почему бы не упростить до:
class Person {
   private void eventOccurs()    {
       react();
       AnotherPerson.react();
   }

   private react()  {
           //Реакция этого персонажа на событие mIdDone;
    }
}


Ну или если так уж хочется через события:
public interface Event {
    void subscribe(Actor a);
}

public interface FullEvent extends Event {
    void fire();
    void addReaction(...)
}

public class Person {
    private final FullEvent fullEvent = new FullEventImpl();

    public getEvent() {
        return new Event() { // Теперь никак нельзя вызвать fire() - ни через приведение типов, ни через рефлексию. 
            @Override
            public subscribe(Actor a) {
                fullEvent.subscribe(a);
            }
        }
    }
    ....
}


UPD выше привели похожее решение.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы