首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从验证后退出的类继承方法的最佳方法是什么?

从验证后退出的类继承方法的最佳方法是什么?
EN

Stack Overflow用户
提问于 2013-10-30 21:34:33
回答 2查看 555关注 0票数 3

在Delphi/Lazarus/FreePascal中,继承从方法退出的父方法验证的最佳方式是什么?假设以下类和方法:

代码语言:javascript
复制
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;

下面的实现将完全隐藏继承的验证和/或重复代码。

代码语言:javascript
复制
{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和出口,但不包括基本的光合作用实现?(见下文)

代码语言:javascript
复制
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;

还有其他想法吗?

EN

回答 2

Stack Overflow用户

发布于 2013-10-30 22:19:39

通过使用策略设计模式避免继承每个行为,如下所示:

这样,您不需要多个TPlant版本,只需要多个行为版本。

代码语言:javascript
复制
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实例的重载函数,您不需要全部重载函数,此处仅用于演示目的:

代码语言:javascript
复制
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.

要点:如果存在低级继承,或者在非常简单的项目中,所有这些都会变成样板。你必须决定是否值得一试,

票数 3
EN

Stack Overflow用户

发布于 2013-10-31 01:37:47

这种简单的情况可以通过将该方法转换为一个函数来轻松解决:

代码语言:javascript
复制
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,在继承链之间再引入一个类。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19683743

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档