通过使用策略设计模式避免对每个行为的继承,如下所示:
这样,您不需要多个 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.
更新:
如果您愿意,您还可以将此模式与工厂结合使用,以确定您希望在每种类型中使用的行为。在下面的代码中,有 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.
重要提示:如果存在低级继承或非常简单的项目,所有这些都将成为样板。您必须决定是否值得一试