прототип Delphi - PullRequest
       43

прототип Delphi

4 голосов
/ 30 марта 2011

Мне было интересно, есть ли что-нибудь в RTTI Delphi, которое будет делать то же самое, что MemberwiseClone в C # для простой реализации шаблона прототипа. Я видел несколько реализаций Delphi этого шаблона, где создается новый объект (TMyObject.Create) и его свойства присваиваются значениям из объекта-прототипа. Я могу ошибаться, но я не вижу пользы от паттерна, если мы создаем объекты таким же базовым способом.

Спасибо.

Ответы [ 5 ]

9 голосов
/ 30 марта 2011

Метод Object.MemberwiseClone делает поверхностную копию объекта, следуя некоторым очень простым правилам и используя преимущества работы .NET-сборщика мусора.

  • Ссылки просто копируются. Это включает в себя строки и ссылки на любые object.
  • Типы значений копируются битами (создаются идентичные клоны).

Часть о типах значений может быть легко продублирована с помощью Delphi. Дублирование поведения ссылочного типа с Delphi, хотя и технически легко, не даст ожидаемого результата: ожидается, что Delphi-код .free создаст объекты, и использует парадигму owner-owned, чтобы убедиться, что это происходит. Обычный шаблон - освободить объекты, созданные владельцем-объектом, от деструктора. Если вы сделаете копию объекта, это приведет к сбою. Вот пример:

  • Объект A имеет ссылку на объект B.
  • Мы создаем объект C как поверхностную копию объекта A. Теперь объект C содержит ссылку на объект B.
  • Освобождаем объект A: A.Free;
  • Мы освобождаем объект B: B.Free; - это автоматически вызывает B.Free, но, к сожалению, B был уже освобожден, когда мы освободили A!

Мы могли бы попытаться сделать deep-copy, как предполагает Дэвид, но это создает некоторые не менее сложные проблемы:

  • Не все объекты следует копировать, например, потому что они инкапсулируют ссылки на реальные ресурсы (например, TFileStream).
  • Некоторые другие объекты не могут быть глубоко скопированы, потому что они находятся в эссессе Singletons. И нет универсального способа сказать: «Этот объект является Singleton, делайте простую справочную копию, не делайте глубокую копию». Пример: копируем ли мы Application?
  • Если вы делаете глубокую копию, у вас могут быть циркулярные ссылки, вам нужно позаботиться об этом. Это не тривиально, и вы начинаете копирование с элемента в коллекции, вы можете оказаться обратно к родителю вашей коллекции, то есть: не совсем ожидаемый результат.
  • Беспорядочное глубокое копирование может занять неожиданные объемы памяти и привести к неожиданным утечкам памяти. Подумайте еще раз о коллекции -> item -> copy item, где вы получите копию «item», но вся COLLECTION была скопирована из-за непредвиденных обратных ссылок.

Собрав все это вместе, мы можем прийти только к одному выводу: у нас не может быть общего назначения, Delphi-эквивалент MemberwiseClone. Мы можем иметь частичное сходство для более простых объектов с несложными взаимодействиями, но это не так привлекательно!

6 голосов
/ 30 марта 2011

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

Если бы вы имели дело с достаточно простыми типами, это бы работало нормально, но вы могли бы легко столкнуться с серьезными проблемами. Например, с макушки головы:

  • Некоторые группы объектов необходимо создавать в определенном порядке.
  • Некоторые члены класса не должны быть клонированы, например, количество ссылок. Как вы узнаете людей с RTTI?
  • Как вы справляетесь с одиночками?
  • А как насчет внешних ссылок, которые нужно настроить? Предположим, вы клонируете объект, который обычно создается фабрикой. Если эта фабрика содержит ссылку на объекты, которые она создает, то движение за спиной может нарушить ваш дизайн.

Вы можете реализовать свой шаблон-прототип, определив базовый метод Clone(), который использует RTTI для простых типов, а затем вам придется переопределить его для чего-то более сложного. Лично я бы унаследовал от TPersistent и сделал бы свой метод Clone() на основе Assign.

4 голосов
/ 08 февраля 2012

В Delphi есть способ выполнить глубокое копирование (клонирование) объекта.Он работает для последних версий Delphi (2010 и выше).Посмотрите приведенный ниже код ... на самом деле он довольно прост и вам не нужны внешние библиотеки.Вы можете найти больше информации здесь: http://www.yanniel.info/2012/02/deep-copy-clone-object-delphi.html

function DeepCopy(aValue: TObject): TObject;
var
  MarshalObj: TJSONMarshal;
  UnMarshalObj: TJSONUnMarshal;
  JSONValue: TJSONValue;
begin
  Result:= nil;
  MarshalObj := TJSONMarshal.Create;
  UnMarshalObj := TJSONUnMarshal.Create;
  try
    JSONValue := MarshalObj.Marshal(aValue);
    try
      if Assigned(JSONValue) then
        Result:= UnMarshalObj.Unmarshal(JSONValue);
    finally
      JSONValue.Free;
    end;
  finally
    MarshalObj.Free;
    UnMarshalObj.Free;
  end;
end;
1 голос
/ 30 марта 2011

Я опубликовал несколько общих компонент клонирования ответить некоторое время назад, что может быть полезно, хотя это не эквивалентно MemberWiseClone.Я думаю, что он работает в Delphi еще в D5, и я уверен, что он работает в D2007.

1 голос
/ 30 марта 2011

Я думаю, вы ищете что-то похожее на это: http://code.google.com/p/delphilhlplib/source/browse/trunk/Library/src/Extensions/DeHL.Cloning.pas

Он будет работать только на D2010 и выше (требуется расширенный RTTI).

...