Передача копии объекта в метод - кто делает копирование? - PullRequest
5 голосов
/ 08 октября 2008

У меня есть объект, который я передаю в вызове метода. Скажем, я использую язык, который позволяет передавать объекты только по ссылке, например, Java или PHP. Если метод вносит изменения в объект, это повлияет на вызывающего. Я не хочу, чтобы это случилось. Похоже, мне нужно сделать копию объекта.

Мой вопрос: кто несет ответственность за клонирование объекта? Вызывающий, прежде чем он вызывает метод? Или вызываемый, прежде чем он меняет объект?

РЕДАКТИРОВАТЬ: Просто чтобы уточнить, я хочу, чтобы это было частью контракта этого метода - что он никогда не изменяет исходный объект. Так что, похоже, все зависит от способа сделать копию. Но тогда у вызывающей стороны нет защиты от метода, который не делает это должным образом. Я думаю, что это приемлемо - похоже, единственной альтернативой является то, что это встроено в язык.

Ответы [ 11 ]

5 голосов
/ 08 октября 2008

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

1 голос
/ 08 октября 2008

Мы могли бы посмотреть на рубин для руководства. Они используют! символ, указывающий, что объект изменен на месте. Таким образом, salary.add (10000) возвращает новый объект, а salary.add! (10000) возвращает исходный объект, но измененный. Вы можете использовать ту же идею в Java или PHP, используя локальное соглашение об именах.

1 голос
/ 08 октября 2008

Итак, вы хотите сделать что-то вроде

MyObject m = new MyObject (); MyObject n = MyObjectProcessor.process (m);?

Мне кажется проще сделать что-то вроде MyObject n = MyObjectProcessor.alter (m.clone ());

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

Что-то похожее на вышесказанное, вероятно, безвредно, если оно четко названо и задокументировано.

1 голос
/ 08 октября 2008

Звонящий. Потому что иногда вы хотите внести изменения в сами объекты, а иногда - в копию.

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

(после вашего) РЕДАКТИРОВАТЬ: В этом случае ответственность за выполнение контракта несет вызывающий абонент, поэтому есть два варианта:

  • вызываемый просто не изменяет объект
  • или вызываемый объект копирует объект и впоследствии работает с копией
0 голосов
/ 08 октября 2008

Если не изменение объекта является частью контракта метода, единственная возможность состоит в том, чтобы сделать копию внутри метода. В противном случае вы лжете своему клиенту.

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

0 голосов
/ 08 октября 2008

Я думаю, что вызывающая сторона должна сделать клон, просто чтобы сделать именование проще. Вы можете назвать свой метод Foo () вместо CloneBarAndFooClone ().

Сравнить:

void RemoveZeroDollarPayments(Order order)

против

Order CloneOrderAndRemoveZeroDollarPaymentsFromClone(Order order)
0 голосов
/ 08 октября 2008

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

0 голосов
/ 08 октября 2008

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

0 голосов
/ 08 октября 2008

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

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

0 голосов
/ 08 октября 2008

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

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