-
Всем добрый день!
Подскажите, пожалуйста, есть ли в Delphi аналоги Си-шных friend-классов?
Напихивание кода в один модуль для того, чтобы была возможность видеть поля класса, меня не устраивает, так как при этом модули разрастаются, превращаясь в кашу. А делать поля класса общедоступными тоже не хочется.
Может, есть какие-нибудь директивы компилятора, или в новых версиях Delphi что-то появилось?
-
> или в новых версиях Delphi что-то появилось?
В новых - это в каких ? В Д7 их точно нет.
А что, без этой самой "дружественности" уж совсем никак не обойтись ? На ней прямо-таки свет клином сошелся ?
-
> есть ли в Delphi аналоги Си-шных friend-классов
Прямых аналогов нет.
> так как при этом модули разрастаются, превращаясь в кашу
А может подойти к вопросу с другой стороны ? 1. Научиться пользоваться Class Explorer. 2. Увеличить mental power skill.
PS: D5 unit Excel2000 - 65957 строк/5 032 718 байт - каши нет :)
-
Есть интерфейсы.
-
> Напихивание кода в один модуль для того, чтобы была возможность > видеть поля класса, меня не устраивает, так как при этом > модули разрастаются, превращаясь в кашу. А делать поля класса > общедоступными тоже не хочется.
Законный способ - размещение в одном модуле. Что-то мне кажется, что такое количество друзей у класса, что в модуле получится каша - это признак плохой архитектуры
-
> А что, без этой самой "дружественности" уж совсем никак > не обойтись ? На ней прямо-таки свет клином сошелся ?
Обойтись, конечно, можно.. И свет на "дружественности" клином не сошелся.. Речь идет только о том, что есть моменты, когда "дружественность" действительно была бы удобна. Я не поклонник Си, но friend-классы считаю удобной вещью для разделения функционала по разным модулям. К примеру, есть класс, отвечающий за выполнение некоторых функций. Рядом есть иерархия классов, отвечающих за отображение данных первого класса на различные визуальные контролы. И плюс - имеется иерархия классов для сохранения данных первого класса в различные хранилища. Так вот, все классы этих двух иерархий обязаны знать о том, как устроен первый класс. Все сваливать в один модуль не очень хочется, а по-другому как?
> Есть интерфейсы.
Замечательно, что они есть )) и пользоваться ими я умею. Но в данном случае это мало чем помогает: все методы интерфейсов - открытые, какой тут может быть разговор об инкапсуляции?
-
> Но в данном случае это мало чем помогает: все методы интерфейсов > - открытые, какой тут может быть разговор об инкапсуляции? >
С интерфейсами просто можно поступить хитро. Закрыть нужные методы класса в приват и сделать их реализациией интерфейса. Тогда клиентский код сможет получить доступ к этим методам только запросив интерфейс. Запрос интерфейса - это будет своего рода "код доступа" и подтверждение, что клиент знает, что делает. Ну а еще уже в самом коде запроса интерфейса можно сделать некую хитрую проверку на то, имеет ли данный код право на доступ к методам.
-
> Vladix (07.05.08 07:59)
> Подскажите, пожалуйста, есть ли в Delphi аналоги Си-шных > friend-классов?
В некотором роде есть.
1. Загоняем нужные поля класса TMyClass в его секцию protected. 2. В другом модуле объявляем: type TMyFriendClass = class(TMyClass); 3. Ниже этого объявления секция protected будет доступна после приведения типа объекта к TMyFriendClass: TMyFriendClass(ObjectOfTMyClass).ProtectedField := ...;
-
> Юрий Зотов © (07.05.08 11:00) [7]
Полагаю, это не совсем то. В данном случае, доступ к закрытим членам получит каждый желающий, а смысл дружественных классов - это разграничение доступа - кому-то доступ разрешен, а кому-то запрещен. Я предлагаю такой вариант: 1. Реализуем в защищаемом классе IInterface и свой интерфейс, содержащий защищаемые методы. 2. Помещаем защищаемые методы в секцию private 3. Реализуем в классе приватное поле (или свойство) AllowAccess: Boolean; 4. Реализуем в классе _QueryInterface таким образом, чтобы он проверял AllowAccess и в случае False не давал доступ к определенному в п.1. интерфейсу. 5. В том же юните реализуем класс-стражник, к которому клиент будет обращаться, когда ему нужен доступ к интерфейсу. 5. У этого класса - один метод: AccessCheck(Client: TObject; Server: TProtectedObject): ISomeInterface. Код этого метода проверяет, имеет ли право Client на доступ (например, ищет класс клиента в неком реестре) и если имеет - выставляет серверу AllowAccess в True, вызывает у него QueryInterface, сбрасывает AllowAccess в False. Если не разрешен - возвращает nil.
-
Хотя нет, так не получится. Клиент, когда запросит интерфейс у объектной ссылки, а не у интерфейсной, это произойдет напрямую через GetInterface, минуя QueryInterface. Так что либо скармливать клиенту интерфейсную ссылку вместо объектной, либо я еще покурю, и что-либо придумаю :)
-
> Подскажите, пожалуйста, есть ли в Delphi аналоги Си-шных > friend-классов?
friend-ы в С++ сделаны от безысходности. Аналогов в Delphi нет, потому что они не нужны.
-
В общем, получилось вот что: type
TProtectedObject = class;
IMyInterface = interface
['']
function GetX: Integer;
end;
TIntfImpl = class(TAggregatedObject, IMyInterface)
private
FController: TProtectedObject;
function GetX: Integer;
public
constructor Create(const Controller: TProtectedObject);
end;
TProtectedObject = class(TObject, IInterface, IMyInterface)
private
X: Integer;
FAllowAccess: Boolean;
FIntfImpl: TIntfImpl;
function GetIntfImpl: IMyInterface;
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
property IntfImpl: IMyInterface read GetIntfImpl implements IMyInterface;
public
constructor Create;
destructor Destroy; override;
end;
TSecurityClass = class
public
class function QueryAccess(Client: TObject; Server: TProtectedObject): IMyInterface;
end;
implementation
function TProtectedObject._AddRef: Integer;
begin
Result := -1;
end;
function TProtectedObject._Release: Integer;
begin
Result := -1;
end;
function TProtectedObject.QueryInterface(const IID: TGUID;
out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
function TProtectedObject.GetIntfImpl: IMyInterface;
begin
if FAllowAccess then
Result := FIntfImpl
else
Result := nil;
end;
constructor TProtectedObject.Create;
begin
inherited Create;
FIntfImpl := TIntfImpl.Create(Self);
end;
destructor TProtectedObject.Destroy;
begin
FIntfImpl.Free;
inherited Destroy;
end;
constructor TIntfImpl.Create(const Controller: TProtectedObject);
begin
inherited Create(Controller as IInterface);
FController := Controller;
end;
function TIntfImpl.GetX: Integer;
begin
Result := FController.X;
end;
class function TSecurityClass.QueryAccess(Client: TObject;
Server: TProtectedObject): IMyInterface;
begin
Result := nil;
if <класс клиента является дружественным> then begin
Server.FAllowAccess := True;
try
Result := Server as IMyInterface;
finally
Server.FAllowAccess := False;
end;
end;
end; Теперь получить доступ к полю X можно только запросом у TSecurityClass. А там - мы полностью контролируем, кому давать доступ, а кому - не давать. Список дружественных классов можно реализовать на основе TClassList.
-
function TProtectedObject.GetIntfImpl: IMyInterface;
begin
if FAllowAccess then
Result := FIntfImpl
else
Result := nil; end;
-
> friend-ы в С++ сделаны от безысходности. Аналогов в Delphi > нет, потому что они не нужны.
Не думаю, что от безысходности, они таким образом просто хотели задать более гибкий механизм управления видимостью, чем это делается обычным образом с помощью директив private/protected/public. Гибкий то он действительно более гибкий, но вот то, что сомнительный - это точно.
-
> Ins ©
Код совсем получился неудобочитаемым.. но самое главное - идея, и она понятна. Спасибо за предложенный вариант!
> Игорь Шевченко © (07.05.08 11:38) [10] > friend-ы в С++ сделаны от безысходности. Аналогов в Delphi > нет, потому что они не нужны.
Ответ, достойный магистра.. Если денег нет, значит они не нужны )))
Что нет в C++ сравнительно с Delphi, чтобы Страуструпу от безысходности пришлось в спешном порядке придумывать "дружественность"? Доступа "всему ко всему" в рамках одного модуля? Если так, то "дружественность" выглядит симпатичнее и по крайней мере объявляется в тексте модулей.
-
Vladix (07.05.08 12:26) [14]
> Что нет в C++ сравнительно с Delphi
Модульности
-
> Ins © (07.05.08 11:11) [8]
> Полагаю, это не совсем то.
Что и было сказано - "в некотором роде".
|