Изменение аргумента сеттера - взломать или нет? - PullRequest
4 голосов
/ 11 января 2009

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

Какое лучшее решение? Чтобы обрезать значение в установщике, например

public void setString(String string) {
    this.string = string.trim();
}

Или обрезать его в вызывающем абоненте (более одного раза), например

object.setString(string.trim());

Или, может быть, что-то еще?

Ответы [ 9 ]

10 голосов
/ 11 января 2009

Да. В конце концов, сеттеры предназначены для такого рода вещей! Для контроля и санации значений, записанных в полях;)

1 голос
/ 12 января 2009

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

public double UserTemperature
{
  get
  {
    return Units.Instance.ConvertFromSystem(UnitType.Temperature, temperature);
  }
  set  
  {
    double v = Units.Instance.ConvertToSystem(UnitType.Temperature, value);
    if (temperature != v)
    {
      temperature = v;
      Changed("SystemTemperature");
      Changed("UserTemperature");
    }
  }
}
0 голосов
/ 05 марта 2013

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

Если кто-то желает разрешить клиенту каким-либо образом изменять состояние объекта, не отвечая приведенному выше описанию, следует использовать метод, а не свойство. Если кто-то вызывает Foo.SetAngle(500), вполне разумно ожидать, что метод будет использовать указанный параметр при установке угла, но свойство Angle может не возвращать угол в той же форме, в которой он был установлен (например, он мог бы вернуть 140) , С другой стороны, если Angle является свойством чтения-записи, можно ожидать, что запись значения 500 будет либо запрещена, либо приведет к тому, что значение будет считано обратно до 500. Если кто-то хочет, чтобы объект сохранял угол в диапазоне от 0 до 359 объект может также иметь свойство только для чтения с именем BaseAngle, которое всегда будет возвращать угол в этой форме.

0 голосов
/ 12 января 2009

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

0 голосов
/ 12 января 2009

Именно поэтому вы используете сеттеры, а не открываете поля объектов всему широкому миру.

Рассмотрим класс с целочисленным углом от 0 до 359 включительно.

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

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

actualVal = passedValue % 360;

Пока это указано в вашем интерфейсе (API), оно совершенно корректно. На самом деле, даже если вы не укажете это, вы все равно можете делать все, что захотите, так как вызывающая сторона нарушила контракт (передав значение за пределы диапазона). Я склонен следовать правилу «как можно скорее очистить ваш вклад».

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

0 голосов
/ 12 января 2009

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

0 голосов
/ 12 января 2009

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

Другой (лучше?) Альтернативой является изменение имени метода на trimAndSetString. Таким образом, не удивительно поведение обрезать ввод.

0 голосов
/ 12 января 2009

Существует две школы: одна говорит, что можно проверять параметр в setter (стиль школы), а вторая говорит, что bean-компоненты не должны содержать никакой логики и только данные (стиль предприятия).

Я верю больше во второй. Как часто вы смотрите на реализацию ваших бинов? getUser должен выбросить любое исключение или просто вернуть null?

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

0 голосов
/ 12 января 2009

Да, конечно. Просто будьте внимательны и проверяйте NULL перед применением любого метода (например, trim ()).

...