Имеет ли смысл создавать интерфейс типа «Копируемый» вместо использования «Клонируемый»? - PullRequest
1 голос
/ 29 июня 2019

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

public class DangerousCallWrapper<T> implements DangerousCaller<T> {
  public T doThing(T dataObject) {

      T cloneOfDataObject = #Clone of dataObject

      // This service modifies the cloneOfDataObject... dangerous! 
      Optional<T> result = service.doThing(cloneOfDataObject);

      return result.orElseThrow(() -> new RuntimeException("No data object returned);
  }
}

public interface DangerousCaller<T> {

  /**
  * Performs the functionality of the DangerousService
  */
  public T doThing(T);
}


public DangerousService<T> {


  public T doThing(T data) {
   data.importantField = null;
   data.thing = "Done!";

   return data;
  }
}

public static void main() {

  DangerousService service = new DangerousService<ImportantObj>();
  ImportantObj important = new ImportantObj().setImportantField("Password for my bank account").setThing("Undone");
  service.doThing(important);
  //would fail this check
  assertNotNull(important.importantField);

  DangerousCallWrapper wrapper = new DangerousCallWrapper<ImportantObj>();
  ImportantObj important = new ImportantObj().setImportantField("Password for my bank account").setThing("Undone");
  service.doThing(important);
  //would not fail this check
  assertNotNull(important.importantField);
}

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

Так что я подумал, что просто добавлю T extends Cloneable к методу ... но я открыл банку с червями, что Cloneable вне табу (https://www.artima.com/intv/bloch13.html). Я также читал, что конструкторы копированиявероятно, это лучший способ справиться с этим ... Однако я не уверен, как обозначить это с помощью обобщений.

Поэтому я подумал о том, чтобы предоставить интерфейс Copyable, который будет делать то, что вы ожидаете Cloneable to do: выставить метод copy(), который создаст новый экземпляр класса.

Это жизнеспособный подход?

1 Ответ

1 голос
/ 02 июля 2019

Чтобы решить вашу проблему, вам нужно полиморфно сделать копию dataObject, например:

T cloneOfDataObject = dataObject.clone();

и проблема в том, что Cloneable не имеет clone() метода, поэтому вышеприведенное не компилируется.

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

interface Copyable<T> {
    public T clone();
}

и связанный тип:

public class DangerousCallWrapper<T extends Copyable<T>> 
    implements DangerousCaller<T> {
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...