Когда вы хотите изменить данные из внешнего объекта, который связан с вашим объектом (у вас есть ссылка на него), я думаю, что может быть лучше использовать подход, который я назвал «Переадресация свойства».
Теперь, в основном, при таком подходе вы определяете свойство в базовом объекте, которое использует как методы получения, так и установки для чтения и записи данных.Но вместо того, чтобы читать данные или записывать данные в какое-то внутреннее поле, как это обычно делают методы получения и установки, вы фактически определяете их таким образом, что вместо этого они читают данные или записывают данные в некоторый внешний объект, либо напрямую обращаясь к этому полю объектовили использовать собственное свойство внешнего объекта для доступа к его данным.Я предлагаю использовать последний, потому что таким образом вы упростите модификацию внешнего объекта без необходимости изменять любой другой объект, который считывает данные или записывает данные в этот внешний объект.
Здесь коротко и, надеюсь, хорошопример закомментированного кода, который покажет вам, как работает такой подход:
type
//Our external object for storing some data
TMyExternalObject = class (TObject)
private
//Field for storing some string value
fStrValue: String;
public
//Property for accessing the value of fStrValue field
property StrValue: String read fStrValue write fStrValue;
end;
//Out base object that will use external object for storing additionall data
TMyBaseObject = class (TObject)
private
//Field for storing reference to our external object
fMyExternalObject: TMyExternalObject;
protected
//Getter method that we will use to forward some data from our external object
function GetMyExternalObjectStr: string;
//Setter method that we will use to store some data into our external object
procedure SetMyExternalObjectStr(AValue: String);
public
//Modified constructor which accepts additional optional parameter so that we can
//set the reference to our external object upon creation of our base class
//If this parameter is omitted when calling constructor the default value of nil will
//be set to AMyExternalObject
constructor Create(AMyExternalObject: TMyExternalObject = nil);
//Property declaration that uses custom made getter and setter methods
property ExternalObjectStr: String read GetMyExternalObjectStr write SetMyExternalObjectStr;
end;
implementation
{ TMyBaseObject }
//Modified constructor which can set fMyExternalObject reference to the object that is passed
//as constructor parameter
constructor TMyBaseObject.Create(AMyExternalObject: TMyExternalObject);
begin
inherited Create;
//Set the reference of external object to the object that was passed as AMyExternalObject parameter
//If parameter was omitted the default value of nil which was defined in constructor will be used
fMyExternalObject := AMyExternalObject;
end;
//Getter method used to forward data from our external object
function TMyBaseObject.GetMyExternalObjectStr: string;
begin
//Always check to se if fMyExternalObject reference is set to point to existing object otherwise you
//will cause AccessVialation by trying to read data from nonexistent object
if fMyExternalObject <> nil then
begin
//Simply assign the returned value from our external object property to the result of the method
result := fMyExternalObject.StrValue;
end
else
begin
//If fmyExternalObject field does not reference to an existing object you will sill want to return
//some predefined result. Not doing so could cause code optimizer to remove this entire method from
//the code before compilation.
//Delphi should warn you about possibility that function might not have a defined result
result := 'No external object attached';
end;
end;
//Setter method used to store some data to external object.
//This method also takes care of creating and linking the external object if one hasn't been linked already
procedure TMyBaseObject.SetMyExternalObjectStr(AValue: String);
begin
//Check to see if fMyExternalObject already references to an existing external object.
//If it does not create external object and set fMyExgternalObject to point to it
if fMyExternalObject = nil then
begin
//Create the external object and set fMyExternalObject field to point to it
fMyExternalObject := TMyExternalObject.Create;
end;
//Write our data to external object
fMyExternalObject.StrValue := AValue;
end;
Обратите внимание, что в этом примере кода нет надлежащей проверки ошибок (потребовалось бы несколько блоков try..except. Я специально пропустил их, чтобы сделатькод более читабелен.
Также мой код написан для работы с классами, а не с компонентами. Поэтому вам придется изменить его для работы с производным компонентом TEdit. Поэтому вам придется изменить объявление конструктора таким образом, чтобычто он не будет скрывать параметры по умолчанию конструктора TEdit.
ПРИМЕЧАНИЕ: хотя мой пример кода позволит вам иметь несколько блоков TEdit, считывающих и изменяющих одно и то же строковое значение, которое хранится во внешнем объекте, это не вызовет всеиз этих коробок TEdit для автоматическогообновляйте их текст при изменении строкового значения внешних объектов.Причина этого заключается в том, что в моем примере кода нет механизма уведомления других блоков TEdit о необходимости перерисовки и отображения нового обновленного текста.
Для этого вам потребуется разработать специальный механизм, который будет уведомлять об этом.все компоненты TEdit, поэтому они должны обновляться самостоятельно.Такой механизм также потребовал бы от вашего внешнего объекта хранить ссылку на все компоненты TEdit, которые ссылаются на него.Если вы решите пойти и внедрить такую систему, обратите особое внимание, потому что такая система будет вызывать циклические ссылки и может помешать автоматическому подсчету ссылок должным образом освободить объекты, когда они больше не нужны.
Здесь может быть неплохо пойтиПрочтите еще немного о компонентной системе уведомлений и о том, как она работает.Зачем?Поскольку целью системы уведомлений компонентов является предоставление таких функциональных возможностей, которые позволяют уведомлять несколько компонентов о некоторых событиях.
ПРЕДУПРЕЖДЕНИЕ. Поскольку в приведенном выше примере кода создаются эти внешние объекты при необходимости, вам необходимо убедиться, чтотакже является правильным кодом для уничтожения созданных внешних объектов, в противном случае вы рискуете их утечь.
Теперь, если у вас есть только один блок TEdit, подключающийся к такому внешнему объекту, вы можете уничтожить его в деструкторе TEdit.Но если вы планируете подключать несколько компонентов TEdit к одному внешнему объекту, вам придется разработать какой-то другой механизм для отслеживания жизни этих внешних объектов.
Надеюсь, мой ответ окажется для вас полезным.
В любом случае, я рекомендую вам прочитать больше об использовании методов получения и установки.Они могут быть довольно мощными при правильном использовании.
PS: Этот подход не новость.Я уверен, что он использовался много раз раньше.Также название «Пересылка собственности», как я его назвал.Вполне возможно, что у него другое имя, которое я не знаю.