По работе захотел воспользоваться паттерном фабричный метод, и спрятать конструктор за protected декларацию.
program ProtectedConstructor; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TBaseClass = class protected FData : string; constructor Create(const AData: string); virtual; public class function FactoryMethod(const Adata: string): TBaseClass; property Data : string read FData; end; type TInheritor = class (TBaseClass) protected constructor Create(const AData: string); override; end; constructor TBaseClass.Create(const AData: string); begin Fdata := Adata; Writeln('TBaseClass.Create'); end; class function TBaseClass.FactoryMethod(const Adata: string): TBaseClass; begin Result := TInheritor.Create(Adata) end; constructor TInheritor.Create(const AData: string); begin inherited; Writeln('TInheritor.Create'); end; var MyClass : TBaseClass; begin try MyClass := TBaseClass.FactoryMethod('Test'); try Writeln(MyClass.Data); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; finally MyClass.Free; Readln; end; end.
Ожидаемое поведение:
Я же решил разнести классы по разным модулям. TBaseClass в одном, и TInheritor в другом.
program BugProtectedConstructor; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, uBaseClass in 'uBaseClass.pas', uInheritor in 'uInheritor.pas'; var MyClass : TBaseClass; begin try MyClass := TBaseClass.FactoryMethod('Test'); try Writeln(MyClass.Data); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; finally MyClass.Free; Readln; end; end.
unit uBaseClass; interface type TBaseClass = class protected FData : string; constructor Create(const AData: string); virtual; public class function FactoryMethod(const Adata: string): TBaseClass; property Data : string read FData; end; implementation uses uInheritor; constructor TBaseClass.Create(const AData: string); begin Fdata := Adata; Writeln('TBaseClass.Create'); end; class function TBaseClass.FactoryMethod(const Adata: string): TBaseClass; begin Result := TInheritor.Create(Adata) end; end.
unit uInheritor; interface uses uBaseClass; type TInheritor = class (TBaseClass) protected constructor Create(const AData: string); override; end; implementation { TInheritorOne } constructor TInheritor.Create(const AData: string); begin inherited; Writeln('TInheritor.create'); end; end.
На выходе:
То есть в перегруженный конструктор мы не попадаем.
И вот вопрос, это баг или фича?
Запостил в quality portal
https://quality.embarcadero.com/browse/RSP-29333
Это ОТЛИЧНАЯ фабрика! Хотя и не совсем "очевидная".
ОтветитьУдалить