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

Как избежать геттеров и сеттеров

Во многих местах я читал, что "геттеры и сеттеры злы". И я понял, почему так. Но я не знаю, как их полностью избежать. Say Item - это класс, который содержит информацию о названии, qty, цене и т.д.... и ItemList - это класс, который имеет список элементов. Чтобы найти общую сумму:

int grandTotal()
{
int total = 0;

for (Item item: itemList)
       total += item.getPrice();

return total;
}

В приведенном выше случае, как избежать getPrice()? Класс Item предоставляет getName, setName и т.д.

Как мне их избежать?

4b9b3361

Ответ 1

Когда вы должны использовать геттеры и сеттеры?

Getters и seters отлично подходят для настройки или определения конфигурации класса или для извлечения данных из модели

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

Вы также можете предоставить геттеры без сеттеров. Они не должны попадать в пары.

Когда вы не должны использовать геттеры и сеттеры?

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

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

Резюме

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

Если у вас есть данные, которые нужно восстановить, но ни при каких обстоятельствах не следует изменять: используйте геттер, но не сеттер.

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

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

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

Также обратите внимание:

Allen Holub article Почему методы getter и setter являются злыми, кажется, является источником аргументации OP, но, на мой взгляд, статья делает плохая работа, объясняющая его точку зрения.

Изменить: Добавлено резюме
Изменить 2: исправления орфографии

Ответ 2

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

  • Getters and setters (accessors) не являются злыми.
  • В большинстве случаев "зло" (ненужно)
  • Инкапсуляция - это не просто добавление доступа к закрытым полям для управления изменениями, ведь есть преимущества нет для добавленных методов get/set, которые просто изменяют частное поле
  • Вы должны написать как можно больше кода с принципом "" Скажите, не спрашивайте"
  • Вы нуждаетесь для использования аксессуаров для кода инфраструктуры, DTO, сериализации и т.д. Не пытайтесь бороться с этим.
  • Вы хотите, чтобы ваша основная логика домена (бизнес-объекты) была как можно более свободной. Вы должны указывать объекты, чтобы делать вещи, а не проверять их внутреннее состояние по своему усмотрению.

Если у вас есть доступ к аксессуарам, вы по существу нарушаете инкапсуляцию. Например:

class Employee
{
   public decimal Salary { get; set; }

   // Methods with behaviour...
}

Это объект домена crap, потому что я могу это сделать:

me.Salary = 100000000.00;

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

Лучшим объектом будет:

class Employee
{
   private decimal salary;

   public void GivePayRise()
   {
        // Should this employee get a pay rise.
        // Apply business logic - get value etc...
        // Give raise
   }

   // More methods with behaviour
}

Теперь мы не можем полагаться на то, что Зарплата является общедоступной. Любой, кто хочет дать заработную плату работникам, должен сделать это с помощью этого метода. Это здорово, потому что бизнес-логика для этого содержится в одном месте. Мы можем изменить это место и повсеместно повсеместно использовать Employee.

Ответ 3

Следующий образец является ярким примером установки и геттеров с шаблонами.

class Item{
  private double price;

  public void setPrice(final double price){
    this.price = price;
  }
  public double getPrice(){
    return this.price;
  }
}

Некоторые кодеры считают, что это называется инкапсуляцией, но на самом деле этот код является точным эквивалентом

class Item{
  public double price;
}

В обоих классах price не защищен или не инкапсулирован, но второй класс легче читается.

 class Item{
    private double price;

    public void setPrice(final double price){
      if(isValidPrice(price))
        this.price = price;
      else throw new IllegalArgumentException(price+" is not valid!");
    }

    public double getPrice(){
      return this.price;
    }
  }

Это реальная инкапсуляция, инвариант класса защищен setPrice. Мой совет - не писать фиктивные геттеры и сеттеры, использовать геттеры и сеттеры только в том случае, если они защищают инвариант вашего класса

Ответ 4

Я читал во многих местах, что "геттеры и сеттеры злы".

Действительно? Это звучит безумно для меня. Многие? Покажи нам. Мы разорвем его на клочки.

И я понял, почему так.

Я этого не делаю. Мне кажется сумасшедшим. Либо вы неправильно поняли, но думаете, что поняли, или оригинальный источник просто сумасшедший.

Но я не знаю, как их полностью избежать.

Вы не должны.

как избежать getPrice?

Видите, почему вы хотите этого избежать? Как еще вы можете получить данные из своих объектов?

как их избежать???

не делать. Прекратите читать безумные разговоры.

Ответ 5

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

Геттеры

Они злы? В коде нет такой вещи, как зло. Код - это код и не является ни хорошим, ни плохим. Это просто вопрос, как трудно читать и отлаживать.

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

"Зло"

Usecase: вы думаете, что хотите цену товара при покупке чего-то.

Люди иногда используют геттеры следующим образом:

if(item.getPrice() <= my_balance) {
   myBank.buyItem(item);
}

В этом коде нет ничего плохого, но это не так прямолинейно, как могло бы быть. Посмотрите на это (более прагматичный подход):

myBank.buyItem(item); //throws NotEnoughBalanceException

Не покупатели или кассиры не проверяют цену товара при покупке. Это на самом деле банковская работа. Представьте, что клиент A имеет SimpleBank.java

public class SimpleBank implements Transaction {

  public void buyItem(Item item){
     if(getCustomer().getBalance() >= item.getPrice()){
        transactionId = doTransaction(item.getPrice());
        sendTransactionOK(transactionId);
     }
  }
}

Первый подход кажется здесь прекрасным. Но что, если у клиента B есть NewAndImprovedBank.java?

public class NewAndImprovedBank implements Transaction {

  public void buyItem(Item item){
     int difference = getCustomer().getBalance() - item.getPrice();
     if (difference >= 0) {
        transactionId = doTransaction(item.getPrice());
        sendTransactionOK(transactionId);
     } else if (difference <= getCustomer().getCreditLimit()){
        transactionId = doTransactionWithCredit(item.getPrice());
        sendTransactionOK(transactionId);
     }
  }
}

Возможно, вы думаете, что используете первый подход, но на самом деле вы ограничиваете возможности своей системы.

Заключение

Не спрашивайте разрешения aka item.getPrice(), попросите прощения aka NotEnoughBalanceException.

Ответ 6

getPrice() обращается к частной переменной, которую я предполагаю.

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

total += item.price;

Однако это обычно считается плохой стиль. Переменные класса обычно остаются закрытыми.

Пожалуйста, просмотрите мой комментарий к вопросу.

Ответ 7

Как избежать геттеров и сеттеров в Java? Используйте Проект Ломбок

Ответ 8

Как избежать геттеров и сеттеров? Дизайн классов, которые фактически действуют на данные, которые они хранят.

В любом случае, Getters лгут о данных. В примере Item.getPrice() я вижу, что получаю int. Но стоит ли цена в долларах или центах? Включает ли он налоги? Что, если я хочу узнать цену в другой стране или штате, могу ли я использовать getPrice()?

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

Ответ 9

"Зло" как .getAttention()

Это часто обсуждалось и даже, возможно, было немного вирусным, в результате уничижительного термина "Зло" , используемого в диалоге. Конечно, есть моменты, когда они вам нужны. Но проблема заключается в их правильном использовании. Видите ли, профессор Голуб заявляет не о том, что делает ваш код сейчас, а о боксе, чтобы изменения в будущем были болезненными и подверженными ошибкам.

Фактически, все, что я прочитал им, несет в себе эту тему.

Как эта тема применяется к классу Элемент?

Посмотрите на будущее элемента

Вот класс элементов fictions:

class Item{
    private double price;

    public void setPrice(final double price){
      if(isValidPrice(price))
        this.price = price;
      else throw new IllegalArgumentException(price+" is not valid!");
    }

    public double getPrice(){
      return this.price;
    }
  }

Это все хорошо и хорошо, но это все еще "Зло" в том смысле, что это может вызвать у вас много горя в будущем.

Скорбь склонна исходить из того факта, что однажды "цена", возможно, придется учитывать разные валюты (и, возможно, даже более сложные бартерные схемы). Установив цену как двойную, любой код, написанный между теперь и "апокалипсисом" (мы говорим "зло", в конце концов, будет проводной ценой до двойной).

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

Вынос на геттеры и сеттеры

Если вы обнаружите, что используете геттеры и сеттеры на простых типах, убедитесь, что вы рассматриваете возможные будущие изменения интерфейса. Существует очень хороший шанс, которого вы не должны быть. Используете ли вы setName(String name)? Вы должны рассмотреть setName(IdentityObject id) или даже setIdentity(IdentityObject id), если появятся другие модели идентификации (аватары, ключи, что угодно). Конечно, вы всегда можете обойти и setAvatar и setKey на все, но, используя объект в вашей сигнатуре метода, вы упростите расширение в будущем объектов, которые могут использовать новые свойства идентификации, а не нарушать наследие объекты.

Ответ 10

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

Решение: создайте другой класс между ними, который хранит ваш элемент в списке элементов и заказанный для этого элемента qty (пусть говорят, что класс называется OrderLine).

OrderLine будет иметь поля Item и qty.

После этого введите код, например calculateTotal (int qty) в Item, который возвращает цену * qty. Создайте метод в OrderLine, который вызывает calculateTotal (qtyOrdered)

Передайте возвращаемое значение в itemList.

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

Ответ 11

Действительно? Я этого не думаю. напротив, геттеры и сеттеры помогают защитить целостность переменных.

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

Ответ 12

Использовать вспомогательный класс ShoppingCart. Item метод item.addTo(ShoppingCart cart) добавит цену в корзину totalSum с помощью shoppingCart.addItem(Item item, int price)

Зависимость от Item до ShoppingCart не является невыгодной, если Item означает элементы ShoppingCart s.

В случае, когда Item живут исключительно для классов ShoppingCart и Item, я бы скорее имел Item как внутренний класс ShoppingCart, так что ShoppingCart > будет иметь доступ к частным переменным элементов.

Другие мысли

Было бы также возможно, хотя и совершенно неинтуитивный дизайн, чтобы класс Item подсчитывал сумму (item.calculateSum(List<Item> items)), так как он может обращаться к частным частям других элементов без нарушения инкапсуляции.

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

Ответ 13

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

http://programmer.97things.oreilly.com/wiki/index.php/Encapsulate_Behavior,_not_Just_State