Inherited class override virtual method dependency
Asked Answered
L

2

10

I have these 2 classes:

type
  TMyBaseClass = class
  protected
    FAllowDoSomething: Boolean; // initialized to False
    procedure DoSomething; virtual;
  end;

  TMyChildClass = class(TMyBaseClass)
  protected
    procedure DoSomething; override;
  end;

implementation

procedure TMyBaseClass.DoSomething;
begin
  if not FAllowDoSomething then Exit; // Abort;
  ShowMessage('TMyBaseClass: FAllowDoSomething is False. You wont see me!');
end;

procedure TMyChildClass.DoSomething;
begin
  inherited; // Must inherit
  // if not FAllowDoSomething then Exit; { I don't want to check here again }
  ShowMessage('TMyChildClass: FAllowDoSomething is False but still I can see this message!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TMyBaseClass.Create do try
    DoSomething;
  finally
    Free;
  end;    

  // if I use Abort in TMyBaseClass, the code will not get here

  with TMyChildClass.Create do try
    DoSomething;
  finally
    Free;
  end;
end;

In TMyChildClass.DoSomething I must inherited the TMyBaseClass.DoSomething but I want it to respect the if not FAllowDoSomething then <don't do anything>.

I have tried using Abort in the TMyBaseClass but I realize it's not a good idea and will break the calling method (TForm1.Button1Click);

What is the correct approach of doing this, without writing the if not FAllowDoSomething then Exit again in TMyChildClass.

Loxodromic answered 13/11, 2013 at 10:39 Comment(0)
C
11

The key point is to perform the check on the boolean once, in the base class. So, make DoSomething non-virtual and implement it in your base class like this:

procedure TMyBaseClass.DoSomething;
begin
  if FAllowDoSomething then
    DoSomethingImplementation;
end;

where DoSomethingImplementation is a virtual method that you override in your derived classes.

The base class then looks like this:

type
  TMyBaseClass = class
  private
    FAllowDoSomething: Boolean;
  protected
    procedure DoSomethingImplementation; virtual;
  public
    procedure DoSomething;
  end;

Your derived class looks like this:

type
  TMyDerivedClass = class(TMyBaseClass)
  protected
    procedure DoSomethingImplementation; override;
  end;

Your overridden method looks like this:

procedure TMyDerivedClass.DoSomethingImplementation;
begin
  inherited;
  ShowMessage(...);
end;
Cleric answered 13/11, 2013 at 10:49 Comment(5)
+1 That's a very common pattern in general if you want the base class to execute something before and/or after the subclass code. Often these method pairs are called Foo (non-virtual) and DoFoo (virtual)Maure
+10 Excellent, and so trivial! :) also +1 for @Maure for mentioning Foo and DoFoo (I was scratching my head thinking how to name these methods and what convention to use).Loxodromic
Yes, naming. I was constrained by your choice of DoSomething. Didn't want to write DoDoSomerthing.Cleric
@David, I agree. Next time I'll use MakeSomthing or simply Foo :)Loxodromic
Anybody know how this pattern is called? I use it quite often and would like to know if there's any name to it. :)Nobility
C
0

You need to catch the Abort exception.

procedure TMyBaseClass.DoSomething;
begin
  if not FAllowDoSomething then Abort;
  ShowMessage('TMyBaseClass: FAllowDoSomething is False. You wont see me!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TMyBaseClass.Create do
  try
    try
      DoSomething;
    finally
      Free;
    end;    
  except
    on EAbort do ;
  end;

  // the code will get here

  with TMyChildClass.Create do
  try
    try
      DoSomething;
    finally
      Free;
    end;    
  except
    on EAbort do ;
  end;
end;
Chinchilla answered 13/11, 2013 at 10:55 Comment(1)
Ouch!! Better hope that nobody else wants to use Abort.Cleric

© 2022 - 2024 — McMap. All rights reserved.