Форум: "Основная";
Текущий архив: 2004.03.28;
Скачать: [xml.tar.bz2];
ВнизАрхитектура приложения Найти похожие ветки
← →
Timego (2004-03-04 16:58) [0]Уважаемые мастера!
Знаю, что вопрос молй описывается во многих книгах и статьях, к которым меня непременно отправят ;) Пишу здесь, потому как хочется узнать живое мнение живых людей, создающих реальные приложения.
В моем приложении есть около десятка глобальных объектов, класс каждого из которых описан в своем модуле. Объекты предназначены для решения конкретных задач, но иногда некоторые объекты "прибегает к услугам" других объектов, то есть обращаются к их свойствам и методам. Например, объект Protocol, инкапсулирующий протокол взаимодействий с сервером, обращается к объектам Log (лог, журнал) и Config (конфигурация). Объект Connector (cоединение) обращается к журналу и протоколу. Единственной проблемой оказывается повторное использование отдельных модулей (классов) в других приложениях, функциональность которых не требует полного набора используемых объектов.
Возможно ли разработать классы таким образом, чтобы степень их связи с другими классами был минимальным, но при этом использование их было таким же простым как и в моем случае?
Чтобы можно было взять класс as is и перенести его в другое приложение.
← →
Тимохов © (2004-03-04 17:05) [1]Если связь есть (например protocol обращается к log) то от этого никуда не дется. Если нужно перенести protocol, то нужно перенести и log или отказаться от его использования, например, через условную компиляцию.
← →
Тимохов © (2004-03-04 17:09) [2]Т.е. одна сущьность полагается на другую сущьность, то в новом проекте первая сущность должна получить адекватную замену. НАпример, может быть такая ситуация:
Проект 1
protocol использует log
Проект 2
есть protocol из проекта 1. Т.к. данный класс в проекте 1 использует log, то и в проекте 2 он также должен иметь адекватную замену. Возможно, что в проекте 2 вы захотите функции ложира переложить на другой класс. В этом случае надо в обоих проетах работать с классом log через интерфейсы, например, создать интерфейс ILog, который по-разному реализовать в проекте 1 и проекте 2.
← →
Никто (2004-03-04 17:11) [3]Вариант 1:
type
TLog = class
public
procedure DoIt;
end;
TConfig = class
public
procedure DoIt;
end;
TProtocol = class
private
m_Config: TConfig;
m_Log: TLog;
procedure DoWithLog;
procedure DoWithConfig;
published
property Log: TLog read m_Log write m_Log;
property Config: TConfig read m_Config write m_Config;
end;
procedure TProtocol.DoWithLog;
begin
if Assigned(Log) then
Log.DoIt;
end;
procedure TProtocol.DoWithConfig;
begin
if Assigned(Config) then
Config.DoIt;
end;
Вариант 2:const
MM_DOIT = WM_USER + $01;
type
TLog = class
private
procedure WMDoIt(var Msg: TMessage); message WM_DOIT;
end;
TConfig = class
private
procedure WMDoIt(var Msg: TMessage); message WM_DOIT;
end;
TProtocol = class
private
m_Config: TObject;
m_Log: TObject;
procedure DoWithLog;
procedure DoWithConfig;
public
property Log: TObject read m_Log write m_Log;
property Config: TObject read m_Config write m_Config;
end;
procedure TProtocol.DoWithLog;
var
Msg: TMessage;
begin
if Assigned(Log) then
begin
...
Log.Dispath(Msg);
end;
end;
procedure TProtocol.DoWithConfig;
var
Msg: TMessage;
begin
if Assigned(Config) then
begin
...
Config.Dispath(Msg);
end;
end;
← →
Тимохов © (2004-03-04 17:19) [4]
> Никто (04.03.04 17:11) [3]
Имхо вариант 2 это синтаксический обман дельфи.
Т.е. обманываем синтаксис дельфи так, чтобы он не ругался при переносе TProtocol в новый проект на отсутствие в нем TConfig. Но если подумать, то это не отвечает на суть вопроса. А что если в TConfig лежат важные параметры, без которых TProtocol работать не может. При этом в новом проекте TConfing не реализован.
Т.о. в данном случае есть потеря функциональности TProtocol.
Мое мнение, что если объекты связаны, то надо переносить их целиком.
Хотя, это уже идеологический вопрос...
← →
Polevi © (2004-03-04 17:20) [5]интерфейсы
← →
Timego (2004-03-04 17:40) [6]
> интерфейсы
Интерфейсы - это здорово, спасибо.
Спасибо и Тимохов, особенно за "создать интерфейс ILog, который по-разному реализовать в проекте 1 и проекте 2".
Только вот получается, что во второй проект должны потянуться ВСЕ без исключения первого проекта. И все методы должны быть перекрыты, даже, если они вообще не нужны во втором приложении.
← →
Timego (2004-03-04 17:39) [7]
> интерфейсы
Интерфейсы - это здорово, спасибо.
Спасибо и Тимохов, особенно за "создать интерфейс ILog, который по-разному реализовать в проекте 1 и проекте 2".
Только вот получается, что во второй проект должны потянуться ВСЕ без исключения первого проекта. И все методы должны быть перекрыты, даже, если они вообще не нужны во втором приложении.
← →
WebErr © (2004-03-04 17:45) [8]
> Timego (04.03.04 17:39) [7]
>
> > интерфейсы
>
>
> Интерфейсы - это здорово, спасибо.
> Спасибо и Тимохов, особенно за "создать интерфейс ILog,
> который по-разному реализовать в проекте 1 и проекте 2".
> Только вот получается, что во второй проект должны потянуться
> ВСЕ без исключения первого проекта. И все методы должны
> быть перекрыты, даже, если они вообще не нужны во втором
> приложении.
Создай общего предка, используй мощь ООП, если не нужны методы, не используй их, просто поднимись к пра-правнуку и заставь его родить ишо што-небуть! :))))
← →
Тимохов © (2004-03-04 17:47) [9]
> Timego (04.03.04 17:40) [6]
Конечно, придется тянуть в другой проект.
Сами подумайте, если protocol полагается на config как он может обойтись без него в новом проекте! Другой вопрос, что можно пересмотреть архитектуру в первом проекте, чтобы "полагание" не было очень сильным. Т.е. есть config хорошо, нет - ну и фиг с ним, обойдемся без него.
← →
Никто (2004-03-04 17:59) [10]
> А что если в TConfig лежат важные параметры, без которых
> TProtocol работать не может. При этом в новом проекте TConfing
> не реализован.
1. Если в TConfig лежат параметры, без которых TProtocol работать не может, то тогда нужно использовать TConfig (или его потомков). (Хотя, функциональность которых не требует полного набора используемых объектов (в вопросе))
2. Или как вариант:procedure TProtocol.DoWithConfig;
begin
if Assigned(Config) then
Param := Config.Param
else
Param := DefaultParam;
end;
3. Или WebErr © (04.03.04 17:45) [8] - использовать абстрактного предка (например, TAbstractConfig).
4. Или интерфейсы, хотя внутри Delphi можно обойтись и без них (см. п. 3).
← →
WebErr © (2004-03-04 18:06) [11]
> 3. Или WebErr © (04.03.04 17:45) [8] - использовать абстрактного
> предка (например, TAbstractConfig).
А чо я в самом конце? :))))
← →
Defunct © (2004-03-04 18:34) [12]Зы, а почему бы как сказал WebErr © (04.03.04 17:45) [8] не использовать вообще общего предка для всех объектов:
Unit BasicClass;
Const ciBasicPrimitive = 0; { ci = ClassID }
...
...
Type
TBasicPrimitive = Class(_)
Private
FClassID : Cardinal;
Public
Constructor Create;Virtual;
Procedure Configure;Virtual;Abstract;
Procedure Load;Virtual;Abstract;
Procedure Save;Virtual;Abstract;
Procedure Tune;Virtual;Abstract;
Procedure Work;Virtual;Abstract;
Procedure LinkWith(Primitive:TBasicPrimitive);Virtual;abstract;
... // Какие-то заранее общие процедуры и функции для всех объект
// По сути это и есть Интрефес
Property ClassID:Cardinal; Read FClassID;
End;
....
Constructor TBasicPrimitive.Create;
Begin
ClassID := ciBasicPrimitive;
End;
End.
Далее все объекты прямым или косвенных образом наследовать от него.
А в вашем объекте протокол использовать не TConfig и TLog а именно, TBasicPrimitive.Unit Unit99;
....
Const ciProtocol = 99;
TProtocol = Class(TBasicPrimitive {или любой другой наследник})
Private
FConfig : TBasicPrimitive;
FLog : TBasicPrimitive;
Public
Constructor Create;Override;
Procedure LinkWith(Primitive:TBasicPrimitive);Override;
End;
Constructor TProtocol.Create;
Begin
Inherited;
ClassID := ciProtocol;
End;
Procedure TProtocol.LinkWith;
Begin
Case Primitive.ClassId Of
ciLog : FLog := Primitive;
ciConfig : FConfig := Primitive;
ciProtocol : FProtocol := Primitive;
End;
End;
....
← →
Defunct © (2004-03-04 18:47) [13]Defunct © (04.03.04 18:34) [12]
Таким образом, при пререносе в другой проект класса TProtocol, Вам будет достаточно перенести вместе с ним только один модуль, в котором описан TBasicPrimitive. Все константы отвечающие за СlassID можно разместить в том же модуле с TBasicPrimitive.
Да ну и я там допустил небольшую ошибку, в кострукторах инициализируется поле FClassID, а не read-only property.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.03.28;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.034 c