什么是Delphi / Lazarus / FreePascal中继承父方法验证的最佳方法? 假设以下类和方法:
type
TPlant = class
public
FIsGreen: Boolean;
procedure DoPhotosynthesis; virtual;
end;
TChildPlant = class(TPlant)
public
procedure DoPhotosynthesis; override;
end;
Implementation
{TPlant}
procedure TPlant.DoPhotosynthesis;
begin
if not FIsGreen then Exit; //TPlants cannot do Photosynthesis if they are not green;
//basic photosynthesis implementation not to be included in child plants
end;
以下实现将完全隐藏继承的验证和/或重复代码。
{TChildPlant}
procedure TChildPlant.DoPhotosynthesis;
begin
if not FIsGreen then Exit; //TPlant descendants cannot do Photosynthesis if they are not green;
//photosynthesis implementation...
end;
正在创建另一种方法,比如DoSpecificPhotosynthesis
,并覆盖它,以实现TChildPlant.DoPhotosynthesis
的实际验证not FIsGreen
并退出但不包括基本光合作用实施的最佳方法? (见下文)
type
TPlant = class
public
IsGreen: Boolean;
procedure DoPhotosynthesis; virtual;
procedure DoSpecificPhotosynthesis: virtual;
end;
TChildPlant = class(TPlant)
public
procedure DoSpecificPhotosynthesis; override;
end;
Implementation
{TPlant}
procedure TPlant.DoPhotosynthesis;
begin
if not FIsGreen then Exit; //TPlants cannot do Photosynthesis if they are not green;
//photosynthesis implementation (child plants must implement their specific way);
DoSpecificPhotosynthesis;
end;
{TChildPlant}
procedure TChildPlant.DoSpecificPhotosynthesis;
begin
//photosynthesis implementation...
end;
还有其他想法吗?
答案 0 :(得分:3)
使用策略设计模式避免继承每个行为,如下所示:
这样,您不需要多个TPlant版本,只需要多个行为版本。
program Strategy;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TPhotosystesisBehavior = class
public
procedure DoPhotosyntesis; virtual; abstract;
end;
TGreenPhotosyntesisBehavior = class(TPhotosystesisBehavior)
public
procedure DoPhotosyntesis; override;
end;
TOtherPhotosynthesisBehavior = class(TPhotosystesisBehavior)
public
procedure DoPhotosyntesis; override;
end;
TPlant = class
private
function GetPhotoBehavior: TPhotosystesisBehavior;
procedure SetPhotoBehavior(const Value: TPhotosystesisBehavior);
protected
FPhotoBehavior: TPhotosystesisBehavior;
public
procedure PerformPhotosyntesis;
property PhotoBehavior: TPhotosystesisBehavior read GetPhotoBehavior write SetPhotoBehavior;
end;
{ TGreenPhotosyntesisBehavior }
procedure TGreenPhotosyntesisBehavior.DoPhotosyntesis;
begin
Writeln(' - Eating some solar energy, delicious!!');
end;
{ TPlant }
function TPlant.GetPhotoBehavior: TPhotosystesisBehavior;
begin
Result:= FPhotoBehavior;
end;
procedure TPlant.PerformPhotosyntesis;
begin
Writeln('Performing Photosynthesis: ');
if Assigned(FPhotoBehavior) then
FPhotoBehavior.DoPhotosyntesis;
Writeln('Performing Photosynthesis: End');
end;
procedure TPlant.SetPhotoBehavior(const Value: TPhotosystesisBehavior);
begin
FPhotoBehavior := Value;
end;
{ TOtherPhotosynthesisBehavior }
procedure TOtherPhotosynthesisBehavior.DoPhotosyntesis;
begin
Writeln(' - I Do not like Solar Enery! ');
end;
procedure TestGreenPlant;
var Plant: TPlant;
GreenPlantBehavior: TGreenPhotosyntesisBehavior;
begin
Writeln('TestGreenPlant: ');
Writeln('');
Plant := TPlant.Create;
Plant.PerformPhotosyntesis;
Writeln('');
GreenPlantBehavior:= TGreenPhotosyntesisBehavior.Create;
Plant.PhotoBehavior := GreenPlantBehavior;
Plant.PerformPhotosyntesis;
Writeln('');
Writeln('TestGreenPlant: End');
Writeln('');
end;
procedure TestOtherPlant;
var Plant: TPlant;
OtherPlantBehavior: TOtherPhotosynthesisBehavior;
begin
Writeln('TestOtherPlant: ');
Writeln('');
Plant := TPlant.Create;
Plant.PerformPhotosyntesis;
Writeln('');
OtherPlantBehavior:= TOtherPhotosynthesisBehavior.Create;
Plant.PhotoBehavior := OtherPlantBehavior;
Plant.PerformPhotosyntesis;
Writeln('');
Writeln('TestOtherPlant: End ');
Writeln('');
end;
begin
TestGreenPlant;
Writeln('--------------');
TestOtherPlant;
Readln;
end.
<强>更新强>
如果您愿意,还可以将此模式与Factory结合使用,以确定要在每种类型中使用的行为。在下面的代码中,有3个重载函数来检索TPlant的实例,你不需要所有这些函数,它仅用于演示目的:
program Strategy;
{$APPTYPE CONSOLE}
uses
SysUtils, TypInfo;
type
TPhotosystesisBehavior = class
public
procedure DoPhotosyntesis; virtual; abstract;
function ToString: String; virtual;
end;
TGreenPhotosyntesisBehavior = class(TPhotosystesisBehavior)
public
procedure DoPhotosyntesis; override;
function ToString: String; override;
end;
TOtherPhotosynthesisBehavior = class(TPhotosystesisBehavior)
public
procedure DoPhotosyntesis; override;
function ToString: String; override;
end;
TBehaviorType = class of TPhotosystesisBehavior;
TEnumBehavior = (GreenPlant, OtherPlant, Unknown);
TPlant = class
private
function GetPhotoBehavior: TPhotosystesisBehavior;
procedure SetPhotoBehavior(const Value: TPhotosystesisBehavior);
protected
FPhotoBehavior: TPhotosystesisBehavior;
public
procedure PerformPhotosyntesis;
property PhotoBehavior: TPhotosystesisBehavior read GetPhotoBehavior write SetPhotoBehavior;
end;
TPlantFactory = class
private
class function InternalGetPlantTyppedInstance(ABehavior: TPhotosystesisBehavior): TPlant;
public
class function GetPlantTyppedInstance(AType: String): TPlant; overload;
class function GetPlantTyppedInstance(AType: TBehaviorType): TPlant; overload;
class function GetPlantTyppedInstance(AType: TEnumBehavior): TPlant; overload;
end;
{ TGreenPhotosyntesisBehavior }
procedure TGreenPhotosyntesisBehavior.DoPhotosyntesis;
begin
Writeln(' - Eating some solar energy, delicious!!');
end;
function TGreenPhotosyntesisBehavior.ToString: String;
begin
Result:= 'TGreenPhotosyntesisBehavior';
end;
{ TPlant }
function TPlant.GetPhotoBehavior: TPhotosystesisBehavior;
begin
Result:= FPhotoBehavior;
end;
procedure TPlant.PerformPhotosyntesis;
begin
Writeln('Performing Photosynthesis: ');
if Assigned(FPhotoBehavior) then
FPhotoBehavior.DoPhotosyntesis;
Writeln('Performing Photosynthesis: End');
end;
procedure TPlant.SetPhotoBehavior(const Value: TPhotosystesisBehavior);
begin
FPhotoBehavior := Value;
end;
{ TOtherPhotosynthesisBehavior }
procedure TOtherPhotosynthesisBehavior.DoPhotosyntesis;
begin
Writeln(' - I Do not like Solar Enery! ');
end;
procedure TestGreenPlant;
var Plant: TPlant;
GreenPlantBehavior: TGreenPhotosyntesisBehavior;
begin
Writeln('TestGreenPlant: ');
Writeln('');
Plant := TPlant.Create;
Plant.PerformPhotosyntesis;
Writeln('');
GreenPlantBehavior:= TGreenPhotosyntesisBehavior.Create;
Plant.PhotoBehavior := GreenPlantBehavior;
Plant.PerformPhotosyntesis;
Writeln('');
Writeln('TestGreenPlant: End');
Writeln('');
end;
procedure TestOtherPlant;
var Plant: TPlant;
OtherPlantBehavior: TOtherPhotosynthesisBehavior;
begin
Writeln('TestOtherPlant: ');
Writeln('');
Plant := TPlant.Create;
Plant.PerformPhotosyntesis;
Writeln('');
OtherPlantBehavior:= TOtherPhotosynthesisBehavior.Create;
Plant.PhotoBehavior := OtherPlantBehavior;
Plant.PerformPhotosyntesis;
Writeln('');
Writeln('TestOtherPlant: End ');
Writeln('');
end;
function TOtherPhotosynthesisBehavior.ToString: String;
begin
Result:= 'TOtherPhotosynthesisBehavior';
end;
{ TPlantFactory }
class function TPlantFactory.GetPlantTyppedInstance(
AType: TBehaviorType): TPlant;
var Behavior : TPhotosystesisBehavior;
begin
Writeln('GetPlantTyppedInstance (TBehaviorType): ');
Writeln('');
Behavior := AType.Create;
Result := InternalGetPlantTyppedInstance(Behavior);
Writeln('');
Writeln(' - GetPlantTyppedInstance (TBehaviorType): Type Created ');
Writeln('');
Writeln('GetPlantTyppedInstance (TBehaviorType): End');
Writeln('');
end;
class function TPlantFactory.GetPlantTyppedInstance(
AType: String): TPlant;
begin
Writeln('GetPlantTyppedInstance (String): ');
Writeln('');
if AType = 'GreenPlant' then
Result := GetPlantTyppedInstance(TGreenPhotosyntesisBehavior)
else if AType = 'OtherPlant' then
Result := GetPlantTyppedInstance(TOtherPhotosynthesisBehavior)
else
raise Exception.Create('Unkown Type');
Writeln('');
Writeln('GetPlantTyppedInstance (String): End');
Writeln('');
end;
class function TPlantFactory.InternalGetPlantTyppedInstance(
ABehavior: TPhotosystesisBehavior): TPlant;
begin
Writeln('GetPlantTyppedInstance (TPhotosystesisBehavior): ');
Writeln('');
Result := TPlant.Create;
Result.PhotoBehavior := ABehavior;
Writeln('');
Writeln('GetPlantTyppedInstance (TPhotosystesisBehavior): Plant Created, Type: '+ABehavior.ToString);
Writeln('');
Writeln('GetPlantTyppedInstance (TPhotosystesisBehavior): End');
Writeln('');
end;
class function TPlantFactory.GetPlantTyppedInstance(AType: TEnumBehavior): TPlant;
begin
Writeln('GetPlantTyppedInstance (TEnumBehavior): ');
Writeln('');
Result := GetPlantTyppedInstance( GetEnumName(TypeInfo(TEnumBehavior) , Ord(AType)) );
Writeln('GetPlantTyppedInstance (TEnumBehavior): End');
Writeln('');
end;
{ TPhotosystesisBehavior }
function TPhotosystesisBehavior.ToString: String;
begin
Result:= 'TPhotosystesisBehavior';
end;
begin
TestGreenPlant;
Writeln('--------------');
TestOtherPlant;
Writeln('--------------');
Writeln('Factory: ');
Writeln('- Green: ');
TPlantFactory.GetPlantTyppedInstance('GreenPlant');
TPlantFactory.GetPlantTyppedInstance(GreenPlant);
TPlantFactory.GetPlantTyppedInstance(TGreenPhotosyntesisBehavior);
Writeln('');
Writeln('- Other: ');
TPlantFactory.GetPlantTyppedInstance('OtherPlant');
TPlantFactory.GetPlantTyppedInstance(OtherPlant);
TPlantFactory.GetPlantTyppedInstance(TOtherPhotosynthesisBehavior);
Readln;
end.
重要: 如果存在低级别继承或非常简单的项目,所有这些都成为样板。您必须决定是否值得拍摄
答案 1 :(得分:2)
通过将该方法转换为函数,可以轻松解决这个简单的情况:
type
TPlant = class(TObject)
private
FIsGreen: Boolean;
protected
function DoPhotosynthesis: Boolean; virtual;
end;
TChildPlant = class(TPlant)
protected
function DoPhotosynthesis: Boolean; override;
end;
implementation
{TPlant}
function TPlant.DoPhotosynthesis: Boolean;
begin
Result := FIsGreen;
if Result then
//Do basic photosynthesis
end;
{ TChildPlant }
function TChildPlant.DoPhotosynthesis: Boolean;
begin
Result := inherited DoPhotosynthesis;
if Result then
//Do specific photosynthesis
end;
但是更复杂的构造可能会受益于实现像Strategy这样的设计模式。
无论如何,您应该问自己FIsGreen
是否属于TPlant
类。如果可以在几个类中划分不同的行为,那么我会:net hesistate在继承链之间再引入一个类。