среда, 25 февраля 2015 г.

Briefly. About factories

In a certain sense following on the theme raised here - Briefly. About triggering the exceptions

Partly following on this theme - Factory Method

How can we create an object?

Of course, in this way:

type
 TmyObject = class
  public
   constructor Create(aSomeData: TSomeData);
 end;//TmyObject

...
var
 myObject : TmyObject;
...
 myObject := TmyObject.Create(aSomeData);

Or in this way:

type
 TmyObject = class
  protected
   constructor Create(aSomeData: TSomeData);
  public
   class function Make(aSomeData: TSomeData): TmyObject;
 end;//TmyObject

...
class function TmyObject.Make(aSomeData: TSomeData): TmyObject;
begin
 if IsValidData(aSomeData) then
  Result := Self.Create(aSomeData)
 else
  Result := nil;
end;
...
var
 myObject : TmyObject;
...
 myObject := TmyObject.Make(theConcreteData);

What is the difference?

The difference is that in "fabric method" certain business logic can be introduced.

In our case it is - IsValidData(aSomeData).

But we can go further:

interface
...
type
 TmyObject = class
  protected
   constructor Create(aSomeData: TSomeData);
   procedure SomeMethodToOverride; virtual;
  public
   class function Make(aSomeData: TSomeData): TmyObject;
 end;//TmyObject
...
implementation
...
 TmySpecialObject = class(TmyObject)
  protected
   procedure SomeMethodToOverride; override;
 end;//TmySpecialObject

...
class function TmyObject.Make(aSomeData: TSomeData): TmyObject;
begin
 if IsMySpecialData(aSomeData) then
  Result := TmySpecialObject.Create(aSomeData) 
 else
 if IsValidData(aSomeData) then
  Result := Self.Create(aSomeData)
 else
  Result := nil;
end;
...
var
 myObject : TmyObject;
...
 myObject := TmyObject.Make(theConcreteData);

And then more further:

interface
...
type
 TmyObject = class
  protected
   constructor Create(aSomeData: TSomeData);
   procedure SomeMethodToOverride; virtual;
  public
   class function Make(aSomeData: TSomeData): TmyObject;
 end;//TmyObject
...
implementation
...
 TmyNULLObject = class(TmyObject)
  protected
   procedure SomeMethodToOverride; override;
 end;//TmyNULLObject

 TmySpecialObject = class(TmyObject)
  protected
   procedure SomeMethodToOverride; override;
 end;//TmySpecialObject

...
class function TmyObject.Make(aSomeData: TSomeData): TmyObject;
begin
 if IsMySpecialData(aSomeData) then
  Result := TmySpecialObject.Create(aSomeData) 
 else
 if IsValidData(aSomeData) then
  Result := Self.Create(aSomeData)
 else
  Result := TmyNULLObject.Create(aSomeData);
end;
...
var
 myObject : TmyObject;
...
 myObject := TmyObject.Make(theConcreteData);

And even more further:

interface
...
type
 ImyInterface = interface
  procedure SomeMethodToOverride;
 end;//ImyInterface

 TmyObject = class(TIntefacedObject, ImyInterface)
  protected
   constructor Create(aSomeData: TSomeData);
   procedure SomeMethodToOverride; virtual;
  public
   class function Make(aSomeData: TSomeData): ImyInterface;
 end;//TmyObject
...
implementation
...
 TmyNULLObject = class(TIntefacedObject, ImyInterface)
  protected
   procedure SomeMethodToOverride;
   // - Of course, we no longer need override here
   constructor Create(aSomeData: TSomeData);
  public
   class function Make(aSomeData: TSomeData): ImyInterface;
   // - and here, generally, we can apply singleton
 end;//TmyNULLObject

 TmySpecialObject = class(TmyObject)
  protected
   procedure SomeMethodToOverride; override;
 end;//TmySpecialObject

...
class function TmyObject.Make(aSomeData: TSomeData): ImyInterface;
begin
 if IsMySpecialData(aSomeData) then
  Result := TmySpecialObject.Create(aSomeData) 
 else
 if IsValidData(aSomeData) then
  Result := Self.Create(aSomeData)
 else
  Result := TmyNULLObject.Make(aSomeData);
end;
...
var
 myObject : ImyInterface;
...
 myObject := TmyObject.Make(theConcreteData);

And that is all.

I hope somebody will like it.

Again I will mention it is only a “model”.

Oh!

One more brief remark.

How can we ensure that we have not “passed the factory”?

I mean ensure that not to call the “parasite default constructor” from TObject.

We can do it in this way:

type
 TmyObject = class
  protected
   constructor Create(aSomeData: TSomeData); overload;
  public
   class function Make(aSomeData: TSomeData): TmyObject;
   constructor Create; overload;
 end;//TmyObject
...
constructor TmyObject.Create;
begin
 Assert(false, 'We should call the factory method, and not the inherited constructor');
end;

We can also do it more “fun”, in this way:

type
 TmyObject = class
  protected
   constructor InternalCreate(aSomeData: TSomeData);
  public
   class function Make(aSomeData: TSomeData): TmyObject;
   procedure Create;
 end;//TmyObject
...
procedure TmyObject.Create;
begin
 Assert(false, 'We should call the factory method, and not the inherited constructor');
end;

In this case error code will not be compiled at all.

Probably, it can be done in this way:

type
 TmyObject = class
  protected
   constructor InternalCreate(aSomeData: TSomeData);
  public
   class function Create(aSomeData: TSomeData): TmyObject;
 end;//TmyObject

Discussion - https://plus.google.com/u/0/113567376800896602748/posts/gkD3a9D1HXp

Комментариев нет:

Отправить комментарий