![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Инкапсуляция и взаимодействие [D7, WinXP]
dvp_Dima © (2005-11-24 21:44:00)Здравствуйте мастера.
При практическом решении задачи возник теоретический вопрос:
Имеются 2 класса:
TLittleClass = class
property FirstProperty: TSomeType;
property SecondProperty: TAnotherType;
end;
TBigClass = class
private
FChanged: Boolean;
FLittleItems: array of TLittleClass;
public
property Changed: Boolean read FChanged;
procedure DoChangeSomething;
...
end;
Т.е. класс TBigClass инкапсулирует класс TLittleClass.
У объекта типа TBigClass имеется свойство Changed (и соответствующее ему поле FChanged), которое предназначено для хранения факта внесения изменений в этот объект.
На практике это означает, что при вызове DoChangeSomething флаг FChanged устанавливается в True;
Вопрос: Как организовать взаимодействие описанной системы, чтобы при внесении изменений в любой из инкапсулированных объектов FLittleItems: array of TLittleClass флаг FChanged устанавливался в True;
Сам я пока нашёл только два решения, но оба они мне не нравятся:
1. В классе TLittleClass сделать аналогичное поле FChanged и поддерживать его значение средствами самого класса. А при вызове TBigClass.Changed возвращять TBigClass.FChanged or TBigClass.FLittleItems[0..Count].FChanged
2. Создать в лкассе TLittleClass свойство OnChange. При создании объекта TBigClass назначить TLittleClass.OnChange действие, устанавливающее флаг TBigClass.FChanged в True.
Подскажите, как правильно организовать это?
dvp_Dima (2005-11-26 21:53:00) [1]Юрий Зотов © (25.11.05 05:31) [5]
Спасибо, думаю это будет действительно правильный подход.
Юрий Зотов (2005-11-25 15:24:00) [2]> Igorek © (25.11.05 08:57) [6]
> Тогда надо реализовать механизм BeginUpdate, EndUpdate...
То есть, повторить все то, что уже сделано в классе TCollection. Значит, надо просто от него и отнаследоваться, это будет и проще, и надежнее.
Igorek (2005-11-25 08:57:00) [3]> 2. Создать в лкассе TLittleClass свойство OnChange. При
> создании объекта TBigClass назначить TLittleClass.OnChange
> действие, устанавливающее флаг TBigClass.FChanged в True.
Вот так хорошо. Но действие - это метод TBigClass, который динамически назначен обработчиком TLittleClass.OnChange (пусть это будет LittleItemChanged(Sender)). Но есть потенциальный недостаток. Вообще говоря поле свойства, должно меняться только в методе записи св-ва. Можно конечно в LittleItemChanged написать Changed := True (предварительно добавив метод записи). Но проблема возникает, когда происходит много изменений, и TBigClass после каждого должен выполнить какую-то затратную операцию (перерисовку например). Вмешаться в работу метода записи напрямую Вы не можете. Тогда надо реализовать механизм BeginUpdate, EndUpdate, IsUpdating - если TBigClass в процессе изменения, то при вызове SetChange, эта затратная операция не выполняется. А в EndUpdate надо инициировать эту затратную операцию.
Юрий Зотов (2005-11-25 05:31:00) [4]> dvp_Dima (24.11.05 21:44)
Наследуйте TLittleClass от TCollectionItem, а TBigClass - от TCollection, там все уже реализовано (см. методы Changed). Или сделайте по аналогии с коллекциями.
ЮЮ (2005-11-25 03:43:00) [5]>Но в этом случае придётся FChanged делать открытым на запись
Зачем? Может лучше
property Changed: Boolean read FChanged write SetChanged
Кстати, будет ли TBigClass.Changed, если в списке нескольких эземпляров TLittleClass был только один, который Changed, и он был удален из списка? Тогда может лучше так(если список не очень большой):
property Changed: Boolean read GetChanged;
function GetChanged: boolean;
var
i: integer;
begin
Result := false;;
for i := 0 to High(FLittleItems) do
if FLittleItems[i].Changed then begin
Result := true;
exit;
end
end;
dvp_Dima (2005-11-25 00:49:00) [6]Т.е. по аналогии с Parent в визуальных компонентах?
Но в этом случае придётся FChanged делать открытым на запись, что конечно не критично, но всё-таки как-то не правильно
oleg_ (2005-11-24 23:21:00) [7]Я в подобных случая для класса littleclass прописываю ссылку на объект класса bigclass
dvp_Dima (2005-11-24 22:04:00) [8]Да, забыл сказать - второй вариант не корректен, потому что TLittleClass.OnChange будет Public и следовательно будет доступен в обход TBigClass