【发布时间】:2011-06-29 10:30:33
【问题描述】:
嗨 我正在尝试在 Delphi 中进行设计模式,由于在 Delphi 中找不到我喜欢的参考资料,我正在转换 O'Reilly C# 3.0 Design Patterns 书中的模式。但这不是问题。我已经从这本书中创建了代理模式,但是我显然不理解 Delphi 接口、构造函数和析构函数以及一般对象生命周期和行为的一些概念。 首先我将发布我的代码:
unit Unit2;
interface
uses
SysUtils;
type
ISubject = interface
['{78E26A3C-A657-4327-93CB-F3EB175AF85A}']
function Request(): string;
end;
TSubject = class
public
function Request(): string;
constructor Create();
end;
TProxy = class (TInterfacedObject, ISubject)
private
FSubject: TSubject;
public
function Request(): String;
destructor Destroy(); override;
end;
TProtectionProxy = class (TInterfacedObject, ISubject)
private
FSubject: TSubject;
FPassword: String;
public
constructor Create();
destructor Destroy(); override;
function Authenticate(supplied: String): String;
function Request(): String;
end;
implementation
{ TSubjectAccessor.TProxy }
destructor TProxy.Destroy;
begin
if Assigned(Self.FSubject) then
FreeAndNil(Self.FSubject);
inherited;
end;
function TProxy.Request: String;
begin
if not Assigned(Self.FSubject) then begin
WriteLn('Subject Inactive');
Self.FSubject := TSubject.Create();
end;
WriteLn('Subject active');
Result := 'Proxy: Call to ' + Self.FSubject.Request();
end;
{ TSubject }
constructor TSubject.Create;
begin
inherited;
end;
function TSubject.Request: string;
begin
Result := 'Subject Request Choose left door' + #10;
end;
{ TProtectionProxy }
function TProtectionProxy.Authenticate(supplied: String): String;
begin
if (supplied <> Self.FPassword) then begin
Result := 'Protection proxy: No Access!';
end else begin
Self.FSubject := TSubject.Create();
Result := 'Protection Proxy: Authenticated';
end;
end;
constructor TProtectionProxy.Create;
begin
Self.FPassword := 'Abracadabra';
end;
destructor TProtectionProxy.Destroy;
begin
if Assigned(Self.FSubject) then
FreeAndNil(Self.FSubject);
inherited;
end;
function TProtectionProxy.Request: String;
begin
if not Assigned(Self.FSubject) then begin
Result := 'Protection Proxy: Authenticate first!';
end else begin
Result := 'Protection Proxy: Call to ' + Self.FSubject.Request();
end;
end;
end.
这些是模式中使用的接口和类。接下来是使用这些类型的代码:
program Structural.Proxy.Pattern;
{$APPTYPE CONSOLE}
uses
SysUtils,
Unit2 in 'Unit2.pas';
var
subject: ISubject;
begin
ReportMemoryLeaksOnShutdown := DebugHook <> 0;
try
WriteLn('Proxy Pattern' + #10);
try
subject := TProxy.Create();
WriteLn(subject.Request());
WriteLn(subject.Request());
subject := TProtectionProxy.Create();
WriteLn(subject.Request());
WriteLn(TProtectionProxy(subject).Authenticate('Secret'));
WriteLn(TProtectionProxy(subject).Authenticate('Abracadabra'));
WriteLn(subject.Request());
ReadLn;
finally
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
只为接口变量分配一个新的对象实例是否合法?我在调试中看到 TProtectionProxy 的构造函数首先执行,然后是 TProxy 的析构函数。 创建 TProtectionProxy 后,应在逻辑中验证 Authenticate('Abracadabra') 但在调试器中,在构造函数中分配 FPassword 时为空?这个非常令人费解。但是当我关闭应用程序时,在析构函数中,密码存在吗? TProtectionProxy(subject) 没问题,但我读到不推荐但(主题为 TProtectionProxy)由于某种原因没有编译(操作员不适用......)? 由于 FSubject 字段,我添加了析构函数。那样可以么? 字段变量是否可以在声明它的同一行启动,或者我需要像在 TProtectionProxy 中那样在构造函数中启动?
我知道我在这里要问的很多,但我个人不认识任何人对 Delphi OOP 非常了解以至于我可以问。
谢谢。
这是适合我的新版本。感谢您的所有帮助。
unit Unit2;
interface
uses
SysUtils;
type
ISubject = interface
['{78E26A3C-A657-4327-93CB-F3EB175AF85A}']
function Request(): string;
end;
IProtected = interface
['{928BA576-0D8D-47FE-9301-DA3D8F9639AF}']
function Authenticate(supplied: string): String;
end;
TSubject = class
public
function Request(): string;
end;
TProxy = class (TInterfacedObject, ISubject)
private
FSubject: TSubject;
public
function Request(): String;
destructor Destroy(); override;
end;
TProtectionProxy = class (TInterfacedObject, ISubject, IProtected)
private
FSubject: TSubject;
const FPassword: String = 'Abracadabra';
public
destructor Destroy(); override;
function Authenticate(supplied: String): String;
function Request(): String;
end;
implementation
{ TSubjectAccessor.TProxy }
destructor TProxy.Destroy;
begin
if Assigned(FSubject) then
FreeAndNil(FSubject);
inherited;
end;
function TProxy.Request: String;
begin
if not Assigned(FSubject) then begin
WriteLn('Subject Inactive');
FSubject := TSubject.Create();
end;
WriteLn('Subject active');
Result := 'Proxy: Call to ' + FSubject.Request();
end;
{ TSubject }
function TSubject.Request: string;
begin
Result := 'Subject Request Choose left door' + #10;
end;
{ TProtectionProxy }
function TProtectionProxy.Authenticate(supplied: String): String;
begin
if (supplied <> FPassword) then begin
Result := 'Protection proxy: No Access!';
end else begin
FSubject := TSubject.Create();
Result := 'Protection Proxy: Authenticated';
end;
end;
destructor TProtectionProxy.Destroy;
begin
if Assigned(FSubject) then
FreeAndNil(FSubject);
inherited;
end;
function TProtectionProxy.Request: String;
begin
if not Assigned(FSubject) then begin
Result := 'Protection Proxy: Authenticate first!';
end else begin
Result := 'Protection Proxy: Call to ' + FSubject.Request();
end;
end;
end.
和程序代码:
program Structural.Proxy.Pattern;
{$APPTYPE CONSOLE}
uses
SysUtils,
Unit2 in 'Unit2.pas';
var
subject: ISubject;
protect: IProtected;
begin
ReportMemoryLeaksOnShutdown := DebugHook <> 0;
try
WriteLn('Proxy Pattern' + #10);
try
subject := TProxy.Create();
WriteLn(subject.Request());
WriteLn(subject.Request());
subject := nil;
subject := TProtectionProxy.Create();
WriteLn(subject.Request());
if Supports(subject, IProtected, protect) then begin
WriteLn(protect.Authenticate('Secret'));
WriteLn(protect.Authenticate('Abracadabra'));
end;
WriteLn(subject.Request());
ReadLn;
finally
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
我已经删除了所有的构造函数,因为现在它们真的什么都不做。并且默认的无参数构造函数是从 TInrefacedObject 继承的,对吗? 我离开了 Self,我想听听为什么不应该使用它?
谢谢
我在http://delphipatterns.blog.com/2011/02/22/proxy-2/ 上有完整的模式实现
【问题讨论】:
-
一些快速提示:除非需要,否则不要使用
Self.。在调用Free(或FreeAndNil)之前不要测试 Assigned(),免费使用nil参考。始终在构造函数中调用inherited;。是的,您将对象构造结果分配给subject是正确的方法。但不要尝试将接口强制转换为对象。如果你想调用Authenticate,通过接口暴露出来。 -
不测试的原因 nil 在 Free id 之前 Free 有效地表示
if Self <> nil then Destroy; -
我使用 Self 的原因是为一个类引用正确的 FSubject 字段。我不应该这样做吗?我认为应该这样使用Assigned。如果变量没有赋值有没有必要FreeAndNil或Free呢? @Garry:对不起,我不太明白你在说什么?你能提供更多细节吗?我想这与我不了解析构函数和 Free 和 FreeAndNil 有关
-
@David Heffernan 和@Garry:这只是为了通知您我的评论。谢谢
-
@elector 最佳实践:
Self是可选的,除非有歧义,否则请忽略它,甚至更好:尽量避免歧义!在免费拨打电话之前,切勿测试Assigned(obj)。请改写FreeAndNil(obj)。
标签: delphi oop design-patterns interface