constructor TMyClass.Create(Int:Integer);
begin
FInt:=Int;
FStr:='none';
FData:=TSomeObject.Create(Int);
end;
constructor TMyClass.(Str:string);
begin
FInt:=0;
FStr:=Str;
FData:=TSomeOtherObject.Create(Str+#32);
end;
И пусть у нас на руках есть экземпляр этого класса MyClass, созданный одним из конструкторов. Возможно ли, имея MyClass создать его копию? Напрашивается что-то типа
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
22-11-2011 04:05 | Сообщение от автора вопроса
2 Роман
Спасибо за развернутый комментарий. Совсем без шишек, боюсь, не получится) И тем не менее ваша "простыня" содержит очень полезные сведения.
2 Fisher
TComponent не вариант, увы. Не дерево даже, а несколько. и из общих предков только TInterfacedObject.
Спасибо.
Остановился на полуавтоматическом варианте. Инициализация спец.методом (реализация интерфейса), уничтожение средой.
На протяжении 5 лет занимаюсь подобными задачами в САПР.
Рассмотрим задачу о возможности или невозможности размещения некого объекта в абстрактном пространстве,
в котором работает Ваш алгоритм (печатная плата, 2D или 3D пространство, железнодорожные колеи...)
Вот какие проблемы, решаемые программистом, можно классифицировать:
1. Размещение нового объекта;
2. Изменение параметров существующего объекта;
3. Перемещение объекта в другое место пространства;
4. Изменение параметров пространства.
Каждая проблема таит в себе много подводных камней, натыкаясь на которые выработался такой подход:
1. Наследование классов объектов, исходя из принципиальных соображений. С высокой долей вероятности любые объекты в предметной области можно классифицировать, найти общие черты, обобщить и вынести в абстракции все, что только можно. Очень удобно, когда предметный класс отличается от предка лишь парой перекрытых виртуальных методов и, может, добавленным конструктором;
2. Представте, что для создания нового объекта в рантайме есть диалог, в котором пользователь вводит все-все его параметры. Абсолютно все. Вам нужно придумать, как в этом случае экземпляр будет создаваться. Я знаю такие подходы:
a) Obj := TObjClass.Create; Obj.Prop1 := aProp1; Obj.Prop2 := aProp2;
b) Obj := TObjClass.Create(aProp1, aProp2);
c) Obj := TObjClass.Create(ObjClassParams);
Первый подход имеет право на существование, но его грамотная реализация требует больше организации, потому что свойства ОБЯЗАНЫ проверяться на корректность значений, что на практике может привести к коллизиям: установка корректных свойств по одному может приводить к исключениям, потому что первое свойство требует УЖЕ установленного второго, а оно еще не установлено.
Второй подход требует создание исчерпывающего конструктора для класса. Этот подход очень удобен там, что есть такое место в программе, где ВОЗМОЖНО проверить все данные комплексно и вынести вердикт, можно или нельзя допустить создание объекта с такими параметрами.
Третий подход очень похож на второй, только параметры объекта сгруппированы в спецкласс-держатель этих параметров. С первого взгляда кажется, что это тавтология, но нет. Спецкласс может проверять корректность параметров ДО ВЫЗОВА КОНСТРУКТОРА объекта, который мы хотим создать в итоге. Напомним, что возбуждение исключения в конструкторе объекта - дурной тон, котрый требует в общем случае очень "осторожного" деструктора, который должен все время проверять внутренние поля, которые распределялись в конструкторах, на существование, прежде чем освобождать память.
3. Проверять корректность изменения некого параметра объекта у меня получилось очень легко, используя спецклассы-держатели параметров объектов. Сначала такой объект создается на основе существующего предметного объекта, в него вносится изменение, проверяется корректность существования в таких параметрах обязательно с возвращением кода ошибки. Если таковой не обнаружено, то уже ставим новое значение в сам объект. Этод подход позволяет одновременно изменять НЕСКОЛЬКО ПРОИЗВОЛЬНЫХ СВОЙСТВ сразу.
4. Измение пространства обрабатывается примерно так же: пространство может делать объект "параметры пространства", который детализирован только до необходимого уровня (ничего лишнего, кроме пространства), в который вносятся изменения (в общем случае их может быть сколько угодно). После чего эти "параметры пространства" подаются на проверку с возвратом кода ошибки всем, кто зависит от этого пространства.
5. Используйте методы классов для программирования правил поведения и функций расчета значений по умолчанию для объектов.
Что все это дает? Избавление от стратегии клонирования мучеников для зверских эксперементов; получается, что "все в белом". Здесь на Королевстве проходила мысль о том, чтобы перестать мыслить синглтонами. На практике это значит, что если логика программы изначально не до конца была продумана и пользователь как-то изменяет габарит контейнера на складе, то при требовании заказчика одновременно изменять габарит у произвольного количества этих контейнеров, Вы можете закричать "шеф, усё пропало!!!" :)
Извините за простыню, шишек понабивали много в свое время. Может, хоть кто-то набьет меньше.
Что можно сказать. Если таких объектов - целое развесистое дерево, то, конечно, логично поручить клонирование себя каждому классу. Тогда CloneSelf каждого потомка сможет использовать inherited, а сам должен будет реализовать клонирование только своих потрохов.
Надо помнить, что в методах клонирования, если создавать их "в лоб", "консервируется" структура объекта, так что при доработке объекта нужно внимательно обновлять соответствующие методы клонирования - достаточно тупая и ответственная работа.
При большом объеме данных, неизбежно возникнет идея это все автоматизировать, и тогда вспомним о published-свойствах и RTTI, и припляшем к упоминавшемуся уже TComponent.
Так сравнивать поведение или состояние?
Я вроде бы нигде не упоминал слово "состояние". Извините, если ввел в заблуждение. Поведение конечно. Само по себе — это задача не из простых, кстати.
Повторюсь еще раз о предполагаемом ходе действий.
1. Создается прототип нужного объекта: Prototype := TTestObject.Create(...);
2. Создается клон: Clone := Prototype.CloneSelf;
3. Клон запускается в "песочницу", и там "работает"; вся "работа" логгируется.
4. По окончании работ клон уничтожается.
5. п.п. 2-4 повторяются нужно число раз.
Нужно сравнивать поведение произвольного объекта в различных ситуациях
Так сравнивать поведение или состояние?
Ведь два объекта могут исходить из одного и того же исходного состояния, и прийти в другое, тоже равное друг другу, состояние, но при этом идти совершенно разными путями, и по пути творить совершенно разные дела - ведь пользующая сторона может вызывать их методы с разными аргументами.
Тогда сравнение полей двух объектов вначале и в конце ничего не даст. Ведь внутреннее состояние не полностью определяет поведение.
Да я уже, собственно, и описал возникшую подзадачу. Нужно сравнивать поведение произвольного объекта в различных ситуациях. Без этого — никак. В целом описать проект у меня нет полномочий, да незачем это.
Соответственно появилась мысль о клонировании: создавать экземпляр единожды, делать по мере необходимости копию и подвергать экзекуциям. По завершении — создавать новую копию и т.д. При условии отсутствия зависимости поведения объекта от адреса размещения эта идея смотрелось неплохо. Но увы, как я и предполагал (и как озвучил Void) слишком много неоднозначностей.
Так что сейчас рассматриваю два подхода: либо все-таки заставлять пользователя каждый раз вызывать конструктор, либо обязать исследуемый объект реализовавывать некий интерфейс с функций клонирования (что-то похожее предложил Всеволод).
p.s.:
Задача интересная, нужная и нерешенная никем ранее..
Это я, естественно, не о клонировании/сериализации (что по сути одно и тоже), не об уборке мусора и даже не об озвученной мной задаче анализа поведения объектов. Это о проекте в целом.
Конечно, было бы гораздо правильнее привести полную формулировку задачи, которая привела меня к необходимости работы с клонами объектов (в качестве одного из вариантов). Однако в силу многих причин это невозможно.
Перефразируя великого Пьера Ферма, можно только сказать, что у присутствующих, скорее всего, есть прекрасное решение Вашей исходной задачи, но привести здесь его полную формулировку в силу многих причин невозможно.
Практически каждый программист со стажем приходил к идее и клонирования, и сериализации, и ленивой загрузки, и автоматического управления мусором. И хорошо, если вовремя обнаруживал, что он не один в этом мире.
Так что рассказывайте, как дошли до жизни до такой.
Требуется проследить, как поведет себя достаточно произвольный объект в некоторых условиях.
Окей, создаем:
Obj1:=TObj.Create;
Тестируем, записываем поведение, уничтожаем.
Создаем еще раз, для тестирования в других условиях этого же объекта:
Obj2:=TObj.Create;
И вот тут — не факт, что Obj1 и Obj2 совпадают с точностью до полей. Вдруг конструктор опирается на какие-то внешние условия? Сравнивать нельзя. Понятно, что даже клонирование — не панацея, по-хорошему нужно клонировать еще и окружение. Возможность клонировать была бы полезна. Жаль, словом...
> Академический интерес - очень стрёмный подход.
Э... я даже не сразу нашелся что ответить... Вроде бы у вас все в порядке с образованием, судя по блогу и публикациям здесь. Не буду навязывать свое виденье, но для новичков оказавшихся здесь поясню, что лично я подразумеваю под "академическим подходом".
Бывает так — перед вами есть задача. Задача интересная, нужная и нерешенная никем ранее (в том смысле, что пока просто никто этим не занимался). И как к ней подступиться, с какого бока подойти к её решению — непонятно. И вот тогда начинается поиск, проба различных подходов... В том числе тех, которые требуют специфических знаний. И тогда есть два пути:
1. Начинать писать код, вырывая с кровью нужные куски из "интернетов", задавая вопросы "а где найти компонент, который решает квадратное уравнение" и т.п. И надеяться, что рано или поздно в результате такого "кодинга" появится на свет программа, решающая поставленную задачу (ну или имеющую видимость этого). Это есть "эмпирический подход", т.е. нахождение решения на практике, путем проб, ошибок и их последовательного исправления (или заворачивания оных в try/except).
2. Подумать, насколько вообще тот или иной подход применим. Немножко копнуть в глубь (возможно под капот языка). Сделать тестовую программу (на несколько порядков проще той, что вам нужна), которая позволит ощутить насколько выбранный подход применим и удобен. И только после этого начинать разработку приложения. Это и есть "академический подход". Хотя он и кажется громоздким и медлительным, на практике при разработке приложения посложнее лабораторных практикумов ВУЗов он оказывается куда как эффективнее.
Соответственно, когда передо мной возникла задача манипуляций с несколькими идентичными (с точностью до значений полей) объектами — я рассмотрел вопрос о возможности клонирования объектов. Как я и отметил в предпоследнем предложении вопроса, таковая возможность сразу же вызывала сомнения. Однако, поскольку я лишь поверхностно знаком с тем как объекты располагаются в памяти — и был задан вопрос, не пропустил ли я чего.
Конечно, было бы гораздо правильнее привести полную формулировку задачи, которая привела меня к необходимости работы с клонами объектов (в качестве одного из вариантов). Однако в силу многих причин это невозможно.
18-11-2011 09:36 | Комментарий к предыдущим ответам
Нужно сказать, что копирование неоднозначная процедура.
+100
@Автор
Академический интерес - очень стрёмный подход. И уважаемый Void на эту тему очень удачно высказался, что я его даже процитировал.
Хочу немного от себя добавить, чуть развивая тему "неоднозначности".
Копирование объекта так или иначе порождает неоднозначность самого объекта.
Что такое, когда у нас в памяти есть два объекта с одинаковым набором полей? Здесь и зарыта "стрёмность". В базах данных это просто запрещено, поэтому разные по размещению записи должны быть уникальны по значению атрибутов (полей). Иначе - кранты.
Объектный подход позволяет сделать разные по размещению объекты с одинаковым набором и значением свойств (данных). Ни к чему хорошему это не приводит. Говоря "академически", видя две ссылки
var
ref1, ref2 : TMyClass;
в некий момент времени (не будем делать гипотезу, что мы знаем, как система пришла в данное состояние) попробуем-ка понять, глядя на ref1 и ref2 - каким объектам они соответствуют?
Возможные варианты:
- ref1 и ref2 указывают на один объект (одно размещение), т.е. ref1 = ref2
- ref1 и ref2 указывают на разные объекты (в памяти), но у них совпадают поля по значениям
Из второго пункта следует неутешительный вывод, что никто не знает, то ли это в материальном мире существуют 2 одинаковых объекта, то ли был склонирован (скопирован) один и тот же объект.
Единственно, что хоть как-то вносит порядок - разнесение ref1 и ref2 по разным областям жизни. Т.е. клонированный объект должен быть более "локальным", чем исходный.
+ если объекты нужно как-то хранить в базе, то без уникального ID не обойтись.
+ копирование объектов массово снижает производительность приложения
+ если уж и копировать, то точно не встроенными методами, чтобы не ошибиться. если уж это ТАК надо, пусть это будет
а) труд программиста, что заставит как минимум подумать еще раз
б) какой-нибудь явный пользовательский метод
Ну и не хочется своим сообщением смазывать главный эффект от предыдущего поста: копирование агрегатов.
Встроенных механизмов нет. Классы должны сами уметь себя копировать используя соответствующие методы и/или конструкторы копирования (в VCL этим занимаются методы Assign, AssignTo).
Нужно сказать, что копирование неоднозначная процедура. Например, если класс содержит поле, являющееся указателем на объект - как осуществлять копирование: созданием аналогичного объекта или просто копированием указателя? Компилятор этого не знает, значит это вопрос проектирования класса.
В простейшем случае можно скопировать область памяти, если экземпляры относятся к одному классу, созданы с одним и тем же выравниванием памяти, и в общем случае не содержат ссылок (строк, объектов и т.п.).
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.