суббота, 1 июля 2023 г.

Обратимся к "истокам"

https://ru.m.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%95%D0%B2%D0%BA%D0%BB%D0%B8%D0%B4%D0%B0

Коротко ещё.

https://vk.com/wall101055118_15494 Модель. А то что не покрыто тестами - так вообще в "серой зоне". И может давать ЛЮБОЙ результат. Пока тесты на это не наткнуться.

Снова с вами. Коротко.

Тестовое покрытие так вообще оказалось помогает программировать. Не тестировать. А именно программировать. Всегда можно написать некую "эмуляцию" того кода, который не понимаешь откуда взять. Но на котором тест падает. Всегда можно написать "заглушку". Типа "на время". И зачастую это "на время" годится "на годы". Главное - хорошее покрытие кода тестами.

вторник, 2 июня 2020 г.

Перегруженный protected constructor. Bug or expected behavior?


По работе захотел воспользоваться паттерном фабричный метод, и спрятать конструктор за 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