开发者

Limiting method access in protected section to few classes

开发者 https://www.devze.com 2023-01-02 19:21 出处:网络
I want to limit the access of protected methods to certain inherited classes only. For example there is a base class like

I want to limit the access of protected methods to certain inherited classes only.

For example there is a base class like

TBase = Class
  Protected
    Method1;
    Method2;
    Method3;
    Method4;
End;

I have two classe开发者_Go百科s derived from TBase

TDerived1 = Class(TBase)
  //Here i must access only Method1,Method2 and Method3
End;

TDerived2 = Class(TBase)
  //Here i must access only Method3 and Method4
End;

Then is it possible to access only Method1, Method2 and Method3 when i use objects of TDerived1 and Method3 and Method4 when i use objects of TDerived2


There's no way to do that. If a method is protected, then all descendant classes have access to it. You might want to rethink your class design if you have two separate sets of functionality that can be divided that easily.


I'd split them, similar to Jeroen's answer:

  TBase = class
  end;

  TBase12 = class(TBase)
  protected
    procedure Method1;
    procedure Method2;
  end;

  TBase34 = class(TBase)
  protected
    procedure Method3;
    procedure Method4;
  end;

  TDerived1 = class(TBase12)
  end;

  TDerived2 = class(TBase34)
  end;

From what you describe, this seems to better model your requirements than a "monolithic" base class (like Mason already wrote).


One more way - you can do this using Interfaces...

IBase1 = interface
  // press Ctrl+Shift+G here to generate your own sexy GUID
  procedure Method1;
  procedure Method2;
end;

IBase2 = interface
  // press Ctrl+Shift+G here again
  procedure Method3;
  procedure Method4;
end;

TBase = class(TInterfacedObject, IBase1, IBase2)
public
  { IBase1 }
  procedure Method1;
  procedure Method2;
  { IBase2 }
  procedure Method3;
  procedure Method4;
end;

var
  B1: IBase1;
  B2: IBase2;
begin
  B1 := TBase.Create as IBase1;
  B2 := TBase.Create as IBase2;

  B1.Method1; // works
  B1.Method3; // Can't compile

  B2.Method3; // works
end;


Seems to me your methods aren't declared in the right place.

If Method1 and Method2 are not called in TBase, and should only be called from TDerived1 and descendents... then those methods should be declared in TDerived1.

If Method1/2 access private fields of TBase, then you should have properties or Getter/setter to those field in TBase.

But unless you give more specific reasons as to why those methods need to be in declared in TBase, I'd say it's just bad design to declare them there.


A solution that works in a similar way to publish private/protected/public properties that works for methods.
So you could do it like this:

unit PropertyAndMethodVisibilityPromotionUnit;

interface

type
  TBase = class
  private
    procedure Method1;
    procedure Method2;
    procedure Method3;
    procedure Method4;
  end;

  TBase1 = class(TBase)
  protected
    procedure Method1;
    procedure Method2;
  end;

  TBase2 = class(TBase)
  protected
    procedure Method3;
    procedure Method4;
  end;

  TDerived1 = class(TBase1)
    //Here i must access only Method1 and Method2
  end;

  TDerived2 = class(TBase2)
    //Here i must access only Method3 and Method4
  end;

implementation

procedure TBase.Method1;
begin

end;

procedure TBase.Method2;
begin

end;

procedure TBase.Method3;
begin

end;

procedure TBase.Method4;
begin

end;

procedure TBase1.Method1;
begin
  inherited;
end;

procedure TBase1.Method2;
begin
  inherited;
end;

procedure TBase2.Method3;
begin
  inherited;
end;

procedure TBase2.Method4;
begin
  inherited;
end;

end.

Notes:

  1. This only works if TBase, TBase1 and TBase2 are in the same unit.
  2. It is a hack working around a potentially weak class design, so be sure you review your class design

--jeroen


ok... Here's a possible way to achieve what you are looking for. I think it requires Delphi 2005 or later though. (Or whatever version that introduced the "Strict Protected|private" visibility)

TBase = Class
  Strict Protected
    procedure Method1;
    procedure Method2;
    procedure Method3;
    procedure Method4;
End;

TDerived1 = Class(TBase)
  Protected
    procedure Method1;
    procedure Method2;
    procedure Method3;   
End;

TDerived2 = Class(TBase)
  Protected
    procedure Method3;
    procedure Method4;
End;

TUserClass = class
  FImplementer : TDerived1;
end;

And the methods look like this

procedure TDerived2.Method3;
begin
  inherited Method3;
end;

But your requirements make me wonder if your method really belongs to your TBase class. Seems they should be static procedure, or maybe class procedure of another class. I don't think they really belong to TBase.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号