В чем смысл геттеров и сеттеров?

Возможный дубликат:
Зачем использовать геттеры и сеттеры?

Я читал книги на Java, говоря, что полезно создавать сеттеры и геттеры для переменных, таких как x и y. Например:

public int getX(){
    return x;
}

public void setX(int x){
    this.x = x;
}

Но в чем отличие от этого и

...(shape.x)...   // basically getX()

и

shape.x = 90;    // basically setX()

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

Ответ 1

Несколько причин:

  • Если вы разрешаете доступ к полю, например

    shape.x = 90

тогда вы не можете добавить какую-либо логику в будущем для проверки данных.

скажем, если x не может быть меньше 100, вы не можете этого сделать, однако если у вас есть сеттеры вроде

public void setShapeValue(int shapeValue){
  if(shapeValue < 100){
    //do something here like throw exception.
  }
}
  • Вы не можете добавить что-то вроде копирования на логике записи (см. CopyOnWriteArrayList)
  • Другая причина заключается в том, что для доступа к полям вне вашего класса вам нужно будет пометить их общедоступными, защищенными или по умолчанию, и, таким образом, вы потеряете контроль. Когда данные являются очень внутренними для класса, разбивающего Encapsulation и вообще OOPS.

Хотя для констант типа

public final String SOMETHING = "SOMETHING";

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

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

Хотя в таких случаях вы должны быть осторожны в методе getter, чтобы убедиться, что вы не выдаете ссылку на объекты (в случае, если ваш класс имеет объект как экземпляры).

Мы можем использовать частные переменные в любом пакете, используя getters и seters.

Ответ 2

Использование функций getter и setter допускает ограничения и инкапсуляцию. Допустим, что x - радиус. shape.x = -10 не имеет большого смысла. Кроме того, если кто-то пытается установить недопустимое значение, вы можете распечатать ошибку, установить значение по умолчанию или ничего не делать.

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

Функции мутаторов
Encapsulation

Ответ 3

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

Один конкретный пример: комплексные числа в математике. Некоторые языки имеют их как язык или структуру, другие - нет. В качестве примера я буду использовать изменяемый класс, но он также может быть неизменным.

Комплексное число можно записать в виде a + bi с вещественной и мнимой частями, хорошо себя зарекомендовав [gs]etRealPart и [gs]etImaginaryPart.

Однако в некоторых случаях легче рассуждать о комплексных числах на полярной форме re^(iθ), давая [gs]etRadius (r) и [gs]etAngle (θ).

Вы также можете выставить методы типа [gs]etComplexNumber(realPart, imaginaryPart) и [gs]etComplexNumber(radius, angle). В зависимости от типов аргументов они могут или не нуждаться в разных именах, но тогда потребитель класса может использовать либо в соответствии с его потребностями.

Две формы взаимозаменяемы; вы можете легко конвертировать из одного в другое, поэтому форма, которую использует класс для внутреннего хранилища, не имеет отношения к потребителям этого класса. Однако потребители могут использовать любую форму. Если вы выберете форму a + bi для внутреннего представления и покажите, что использование полей, а не геттеров и сеттеров, вы не только вынуждаете потребителей классов использовать эту форму, вы также не можете впоследствии легко изменить свое мнение и заменить внутреннее представление на re ^ (iθ), потому что это оказывается более простым в реализации в вашем конкретном сценарии. Вы застряли с общедоступным API, который вы определили, и который предусматривает, что конкретно реальные и мнимые части отображаются с использованием определенных имен полей.

Ответ 4

Одна из лучших причин, по которым я могу думать о геттерах и сеттерах, - это постоянство API класса. В таких языках, как python, вы можете получить доступ к членам по их имени и позже переключать их на методы. Потому что функции ведут себя по-разному, чем члены в java, как только вы обращаетесь к его собственному свойству. Ограничивая его область действия, ломается клиент.

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

Ответ 5

Еще одна веская причина для пользователя-получателя и сеттера можно понять в следующем примере

public class TestGetterSetter{
    private String name ;


    public void setName(String name){
        this.name = name ;
    }


    public String getName(String name){
        return this.name ;
    }
}

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

Представьте, что вы используете имя вместо его получателя. Затем, если вы хотите добавить что-то вроде значения по умолчанию (скажем, имя по умолчанию - "Гость", если оно не было установлено ранее), вам придется изменить функцию getter и sayName.

public class TestGetterSetter{
    private String name ;


    public void setName(String name){
        this.name = name ;
    }


    public String getName(String name){
        if (this.name == null ){
            setName("Guest");
        }
        return this.name ;
    }
}

Для геттеров и setter нет необходимости начинать с get и set - они являются просто нормальными функциями-членами. Однако это соглашение для этого. (особенно если вы используете Java Beans)

Ответ 6

Первоначально, шаблон getter/setter был создан для обеспечения хорошего объектно-ориентированного дизайна encapsulating внутренними элементами class из его внешнего interface.

  • Скрытие внутреннего представления свойства

это лучший ответ на ваш вопрос Зачем использовать геттеры и сеттеры?

Ответ 7

Скажем, гипотетически, вы найдете библиотеку, которая лучше справляется с тем, что вы делали в своем классе (YourClass). Естественно, что на этом этапе нужно сделать интерфейс YourClass оболочкой для этой библиотеки. Он по-прежнему имеет концепцию "X", которую должен получить или установить ваш клиентский код. Естественно, на этом этапе вам в значительной степени нужно написать функции доступа.

Если вы пренебрегли использованием функций доступа и позволили своему клиенту получить доступ к YourClass.x напрямую, вам теперь придется переписать весь код вашего клиента, который когда-либо касался YourClass.x. Но если вы использовали YourClass.getX() и YourClass.setX() с самого начала, вам нужно будет только переписать YourClass.

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

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

Ответ 8

Есть много причин. Вот лишь несколько.

  • Аксессоры, в частности, получатели, часто появляются в интерфейсах. Вы не можете указывать переменную-член в интерфейсе.
  • Как только вы обнаружите эту переменную-член, вы не можете изменить свое мнение о том, как она реализована. Например, если позже вы захотите переключиться на такой шаблон, как агрегация, где вы хотите, чтобы свойство "x" действительно было связано с каким-либо вложенным объектом, вам нужно скопировать это значение и попытаться сохранить его в синхронизации. Нехорошо.
  • В большинстве случаев вам намного лучше не подвергать сеттера. Вы не можете сделать это с помощью общедоступных полей, таких как x.

Ответ 9

Прежде чем попасть в ответ, мы должны знать что-то раньше...! " JavaBeans".
JavaBeans - это классы Java, обладающие свойствами. Для наших целей подумайте о свойствах как переменных частного экземпляра. поскольку они являются частными, единственный способ доступа к ним из-за пределов своего класса через "методы" в классе.
 Методы, которые меняют правильное значение, называются методами setter, а методы, которые извлекают значение свойства, называются методами getter.

Ответ 10

Я бы сказал, что ни геттеры/сеттеры, ни публичные участники не являются объектно-ориентированным дизайном. Они оба прерывают инкапсуляцию ООП, обнажая данные объектов в мире, которые, вероятно, не должны вообще обращаться к свойствам объекта.

Ответ 11

Это делается с помощью принципа encapsulation для ООП.

Языковой механизм для ограничения доступа к некоторым компонентам объекта.

Это означает, что вы должны определить видимость для атрибутов и методов ваших классов. Существует 3 общие возможности:

  • Закрыто: только класс может видеть и использовать атрибуты/методы.
  • Защищено: только класс и его дети могут видеть и использовать атрибуты/методы.
  • Public: каждый класс может видеть и использовать атрибуты/методы.

Когда вы объявляете частные/защищенные атрибуты, вам рекомендуется создавать методы для получения значения (get) и изменять значение (set). Один пример о видимости - это класс [ArrayList][2]: он имеет свойство size, чтобы узнать фактический размер внутреннего массива. Только класс должен изменить его значение, поэтому код выглядит как

public class ArrayList<E> {
    private int size;
    private Object[] array;
    public getSize() {
        return this.size;
    }
    public void add(E element) {
        //logic to add the element in the array...
        this.size++;
    }
}

В этом примере вы можете увидеть, что значение размера может изменяться только внутри методов класса, и вы можете получить фактический размер, вызвав его в своем коде (не изменяя его):

public void someMethod() {
    List<String> ls = new ArrayList<String>();
    //adding values
    ls.add("Hello");
    ls.add("World");
    for(int i = 0; i < ls.size(); i++) {
        System.out.println(ls.get(i));
    }
}

Ответ 12

Getters и seters инкапсулируют поля класса, делая их доступными только через свои общедоступные методы и сохраняя значения самими частными. Это считается хорошим принципом ОО.

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

Ответ 13

Потому что мы используем язык объектно-ориентированного программирования. Здесь мы используем скрытие данных и инкапсуляцию. Эта переменная не должна быть напрямую доступна из внешнего мира (для обеспечения скрытия данных), поэтому мы создадим ее конфиденциально, поэтому

shape.x

неверно. Метод getter и setter используется для получения и установки значения x, которое является способом достижения инкапсуляции.