Подтвердить что ты не робот

Каковы альтернативы публичным полям?

Я программирую игру в java, и в качестве заголовка вопроса я использую публичные поля в своих классах. (пока)

Из того, что я видел, публичные поля плохие, и я понимаю, почему. (но если кто-то может уточнить, почему вы не должны их использовать, это будет оценено)

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

Итак, мой вопрос в том, каковы альтернативы? или мне действительно нужно использовать частные поля с геттерами и сеттерами?

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

Я буду более подробно рассказывать, если это необходимо.

public double health;
//The player fields.
public String name;
public double goldCount;
public double maxWeight;
public double currentWeight;
public double maxBackPckSlts;
public double usedBackPckSlts; // The current back pack slots in use
public double maxHealth; // Maximum amount of health
public ArrayList<String> backPack = new ArrayList<String>();

//This method happens when ever the player dynamically takes damage(i.e. when it is not scripted for the player to take damage.
//Parameters will be added to make it dynamic so the player can take any spread of damage.
public void beDamaged(double damage)
{
    this.health -= damage;
    if (this.health < 0)
    {
        this.health = 0;
    }
}

EDIT: для проверки этого класса мой класс Weapon выглядит следующим образом: (Пример кода почему-то не работает, поэтому он выглядит не так.)

private final double DAMAGE;
private final double SPEED;

public Weapon(double initialDmg,double initialSpd,String startName,double initialWg)
{
    DAMAGE = initialDmg;
    SPEED = initialSpd;
    setItemName(startName);
    setItemWeight(initialWg);
}

public double getSpeed() 
{
    return SPEED;
}


public double getDamage()
{
    return DAMAGE;
}

Как вы можете видеть, поскольку параметры Weapon's DAMAGE и SPEED не нуждаются в изменении, они могут быть окончательными на данный момент. (если позже в игре я решил, что эти значения могут быть "Обновлены", так сказать, я могу добавить сеттеры, затем с проверкой или просто создать новое оружие с обновленными значениями). Они устанавливаются в конструкторе Weapon's.

Заключение: геттеры и сеттеры в порядке, если они используются умно и используются только тогда, когда это необходимо. (Однако)

4b9b3361

Ответ 1

Общепринято использовать геттеры и сеттеры вместо того, чтобы давать другим объектам разрешение на изменение ваших полей напрямую. Это может не иметь никакого смысла, если вы увидите, что 99,99% ваших геттеров и сеттеров не делают ничего, кроме того, что вы могли бы сделать с прямым доступом к полям. Но что происходит, когда вы решаете, что, когда игрок поврежден за точку, он бросает половину своего инвентаря? Или вы хотите ограничить, сколько слотов для рюкзаков можно использовать магическими предметами? Вы либо должны выслеживать все места в вашем коде, где вы изменяете поля, или, если вы использовали геттеры и сеттеры, вы делаете изменения полностью в классе. Это сердце объектно-ориентированного программирования - что вы инкапсулировали "знание" того, что делает объект внутри самого объекта, а не распространять его среди всех объектов, которые взаимодействуют с этим объектом.

Ответ 2

Одна из основных концепций объектно-ориентированного программирования - encapsulation - то есть, скрывая состояние объекта (например, данные в объекте) извне и позволяя объекту обрабатывать его собственное состояние.

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

Я думаю, что ваш код уже начинает использовать инкапсуляцию.

Посмотрим на код

Посмотрим на метод beDamaged.

public void beDamaged(double damage)
{
    this.health -= damage;

    if (this.health < 0)
    {
        this.health = 0;
    }
}

Здесь мы видим, что этот метод будет вызываться внешним миром, и это повлияет на здоровье игрока. Он также содержит логику, поэтому здоровье не может быть отрицательным числом. Проигрыватель beDamaged, который вы написали, сохраняет состояние объекта в пределах параметров, которые вы определили как допустимые.

Оставьте сообщение о игроке

Теперь, из приведенного выше, я думаю, что могу сделать вывод о объекте игрока:

Игрок health не может быть отрицательным числом.

Является ли то, что мы предположили всегда верно?

Посмотрите, может ли это быть всегда истинным из кода, который вы предоставили.

Ага! У нас здесь небольшая проблема:

public double health;

Если поле health равно public, внешний мир может непосредственно манипулировать полем, чтобы помещать состояние объекта игрока в одно, которое, вероятно, не желательно, некоторым кодом, например следующим:

Player player = new Player();
player.health = -100

Я собираюсь предположить, что игрок не должен находиться в состоянии, когда health является отрицательным числом.

Что мы можем с этим сделать?

Как этого можно было избежать? - с полем health private.

Теперь единственный способ повлиять на плеер health будет с помощью методов beDamaged и gainHealth, и это, вероятно, правильный способ для внешнего мира повлиять на здоровье вашего плеера.

Что также означает это - когда вы создаете поле private, это автоматически не означает, что вы должны создавать геттеры и сеттеры для поля.

Частные поля не требуют получения и настройки

Getters и seters обычно являются способом прямого воздействия на поле, которое имеет объект, возможно, с некоторой валидацией, чтобы предотвратить неправильный ввод, чтобы ваш объект имел состояние, которого он не должен, но будут моменты, когда сам объект должен отвечать за воздействие на данные, а не на внешний объект.

Ответ 3

В Java использование частных полей с помощью getters/seters - рекомендуемая практика, , если внешние клиенты вашего класса действительно нуждаются в доступе к этим полям.

В противном случае сохраните их как частные поля и просто не предоставляйте getter/setter.

Существуют различные причины, по которым это наилучшая практика:

  • Если клиенты используют ваше поле напрямую, а потом что-то нужно изменить в этом отношении, вы застряли. С помощью геттера вы можете делать много всего до того, как вы получите доступ к полю.
  • Есть что-то, называемое спецификацией JavaBeans, которая требует от вас использовать getter/setters. Без них ваш класс (тогда называемый bean) не будет взаимодействовать с этим. JSP и JSF EL - один из примеров того, что требовало, чтобы ваш класс соответствовал стандартам JavaBeans.

<суб > (p.s. не связаны с вашим вопросом, но вам лучше не объявлять backPack как ArrayList. Объявлять как List, код для интерфейса, а не для реализации) Суб >

Ответ 4

Если у вас есть частное поле с методом get() и метод set(), который ничего не делает, кроме как извлекать и присваивать значение, вы должны просто сделать поле общедоступным, так как это поле не реально частные, а геттеры и сеттеры только ухудшают производительность. Если геттеры и сеттеры проверяют установленное значение или если значение разрешено извлекать, тогда идите и используйте геттеры и сеттеры. например Если у вас есть переменная private int width;, и кто-то пытается вставить -1 с установщиком, а сеттер убедится, что он не является отрицательным, то это полезно. Например:

private int width;
public int get(){
    return width;
}
public void set(int w){
    if (w < 0) throw new RuntimeException();
    else width = w;
}

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

Итак, короткая короткая история:

Используйте геттеры и сеттеры, когда делаете что-либо, кроме получения или назначения значения. Кроме того, просто используйте общедоступные поля.

то есть.

ПЛОХО:

private int width;
public int get(){
    return width;
}
public void set(int w){
    width = w;
}

ХОРОШО:

private int width;
public int get(){
    return width;
}
public void set(int w){
    if (w < 0) throw new RuntimeException();
    else width = w;
}

ХОРОШЕЕ, если вы не хотите ничего, кроме получения или настройки:

public int width;

Ответ 5

Об этом:

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

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

Для каждого поля, которое у вас есть, вы должны проверить:

a) нужен ли Getter (другие классы должны знать значение этого поля)
 b) нужен ли сеттер (другие классы должны иметь возможность изменять значение этого поля)
 в) или поле должно быть неизменным (окончательным), если оно должно быть инициализировано во время определения или конструктора (и, очевидно, не имеет никакого сеттера)

Но вы вряд ли когда-либо (исключение: объекты значения) предполагаете, что все частные поля будут иметь геттеры и сеттеры и пусть ваша среда IDE генерирует их все.

Ответ 6

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

Ответ 7

частные поля и сеттеры и геттеры действительно ваш лучший способ пойти.

Обратите внимание, что это вообще хороший код на любом языке, поскольку он сохраняет вашу безопасность красивой и жесткой, а также дает вам структуру, которая намного легче отлаживать и поддерживать. (Не забудьте указать документ btw!)

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

Ответ 8

Getters и seters являются частью открытого интерфейса вашего класса. Это контракт между разработчиком/разработчиком класса и пользователями этого класса. Когда вы определяете геттеры и сеттеры, вы должны быть уверены, что будете поддерживать их в будущих версиях.

Атрибуты должны соответствовать только реализации данной версии класса. Таким образом, разработчик класса может в одностороннем порядке изменить реализацию, следовательно, поле, не нарушая его обязательства поддерживать интерфейсы.

Вот пример. Рассмотрим класс под названием Point. Если вы решите, что точка имеет общедоступные атрибуты x и y, вы никогда не сможете ее изменить. Напротив, если у вас есть методы/методы X/Y, последующие версии класса могут использовать различные внутренние представления: прямоугольные координаты (x, y), но также полярные (r, тета) и т.д. Все это без изменения публики интерфейс.

Ответ 9

Более короткая версия ваших методов...

public void beDamaged(double damage) {
    health = Math.max(0, health-damage);
}

public void gainHealth(double gainedHp) {
    health = Math.min(maxHealth, health + gainedHp);
}

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

public void adjustHealth(double adjustHp) {
    health = Math.max(0, Math.min(maxHealth, health + adjustHp));
}

Ответ 10

Если вы не поддерживаете какие-либо инварианты, тогда общественные поля - это путь. Если вам нужен инвариант для нескольких членов, вам понадобятся частные поля и инкапсуляция.

Но если вы не можете придумать какие-либо лучшие имена, чем GetFoo и SetFoo для методов, это хорошая подсказка, что ваши геттеры и сеттеры, вероятно, бесполезны.

Ответ 11

.... жалкое содержание опущено....

ИЗМЕНИТЬ

Извините за то, что вы слишком жалкие - должны быть таблетки... Другие ответы весьма актуальны и хороши

Ответ 12

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

Кстати, концепция использования смеси постоянных и изменяемых объектов в приключении восходит по крайней мере до 1980 года. В картридже Warren Robinett "Adventure" для 2600 каждый объект имеет несколько указателей, хранящихся в ПЗУ, для таких вещей, как позиции и состояния, поэтому объекты, которые не собираются двигаться (например, замковые ворота или "подпись" ), не должны иметь свою позицию, хранящуюся в ОЗУ, и большинство захваченных объектов (которые не имеют никакого состояния другое чем их положение) не нужно будет сохранять состояние в ОЗУ, но анимированные объекты, такие как драконы и летучие мыши, могут хранить как состояние, так и положение в ОЗУ. На машине с общим объемом памяти 128 байт такая экономия была критической.