Я пишу игровой механизм в Java для двух карточных игр плеера, для которых мои студенты собираются записать плеерам AI.
Плееры AI будут сменяться, играя в карты на их 'поле' часть 'таблицы' перед ними. Они могут напасть картой от их поля на карту в поле другого игрока. Карты могут быть поверхностью или победить.
Класс GameEngine позволяет плееру AI принимать его оборот путем вызова GamePlayer. TakeTurn (инженер GameEngine) метод. Игрок может попросить у игрового механизма поля игрока защиты, таким образом, плеер может принять решения на основе количества карт там и которые поверхность. Скажем, этим методом является GameEngine. GetDefendingField ()
Теперь, я хочу удостовериться, что нападающий игрок не может изменить поле игрока защиты или карты в поле игрока защиты и что нападающий игрок может только определить поверхность карты в поле плееров защиты.
У меня есть классы для Карты, Поле (ArrayList Карт), GamePlayer и GameEngine. Там какой-либо путь состоит в том, чтобы создать интерфейс для Поля так, чтобы GameEngine мог возвратить поле игрока защиты без способности плеера нападения изменить его? и без способности плеера нападения переделать поле игрока защиты во что-то, что может быть изменено.
У меня может быть GameEngine. GetDefendingField () возвращают интерфейс только для чтения в Поле, которое не может быть переделано к Полю?
tia,
Sh-
Если вы хотите добиться этого без копирования и без возможности приведения ссылки на интерфейс только для чтения к соответствующему интерфейсу для чтения и записи, вы можете попробовать использовать подход обертки.
Для такого интерфейса:
interface Info {
String getInfoA();
void setInfoA(String infoA);
String getInfoB();
void setInfoB(String infoB);
}
Вы можете создать обертку readonly, которая игнорирует сеттеры или выбрасывает исключения, например:
class ReadonlyInfo implements Info {
final Info instance;
ReadonlyInfo(Info info) {
if (null == info) { throw new InvalidArgumentException(); }
instance = info;
}
String getInfoA() { return instance.getInfoA(); }
void setInfoA(String infoA) { /** silent ignore */ }
String getInfoB() { return instance.getInfoB(); }
void setInfoB(String infoA) { throw new IllegalStateException(); }
}
Используя подход обертки, вы можете использовать полиморфизм на стороне клиента, быть в безопасности от приведения ссылки для получения больших прав доступа и выбирать между молчаливым игнорированием вызванных сеттеров или выбрасыванием исключения незаконного доступа.
Примечание: конечно, вы не будете защищены от кода, который использует отражение для получения обернутого объекта.
Здесь вы говорите об основном модели-представлении-контроллере, где ваша модель - это карта и поле, контроллер - это GamePlayer и GameEngine, а представление пока еще не определено. Ваше поле - это ваша модель, и вы хотите создать 2 разных интерфейса, которые будут обращаться к модели поля, один только для чтения и один для чтения-записи. Ваша реализация чтения-записи, скорее всего, просто вернет объект Field. Ваша реализация только для чтения будет проходить через элементы в Поле и возвращать только те, к которым у них есть доступ, делая глубокую копию каждой возвращенной Карты в Поле.
Вы определенно можете это сделать. В литературе по возможностям объектов этот подход называется затуханием . Пока ограниченный тип не определен как подтип мощного типа, приведение объекта не будет предоставлять больше полномочий.
Мне нравится идея использования безопасности типов и полиморфизма для управления такого рода контроль доступа во время компиляции, особенно при обучении.
Хороший способ приблизиться к этому - иметь два полевых интерфейса. Возможно, Field и MutableField, где последнее расширяет первое и добавляет методы изменения. Ваш FieldImpl, конечно, может реализовать и то, и другое.
Проблема, конечно же, в том, что вы хотите вернуть различные объявленные типы (Field или MutableField) из вашего игрового движка в зависимости от того, чье поле вы используете. Если у вас одна модель, вы можете использовать что-то вроде getMyField () и getOtherPlayerField (), поскольку из описания видно, что при вызове getField () человек точно знает, какое именно поле ему нужно.
Вы можете создать интерфейс только для чтения, который имеет только геттеры. Расширение этого интерфейса будет интерфейсом чтения-записи, который добавляет сеттеры.
Вы не можете определить интерфейс Java, который обеспечивает доступ только для чтения к полям / члены, поскольку это деталь реализации, определенная в классе. (Действительно, то, как вы храните данные внутри, является деталью реализации)
Я бы предложил создать две реализации вашего интерфейса Field, одну с доступом только для чтения, а другую с доступом для чтения / редактирования. Вы можете сделать так, чтобы каждый класс реализовал интерфейс Field, возможно, с классом AbstractField в качестве родительского класса каждого, чтобы охватить общие функции.
Затем у вас могут быть конструкторы для каждого конкретного класса (только для чтения и для чтения / записи) для преобразования между ними, если это необходимо.