четверг, 4 сентября 2014 г.

Коротко. И ещё о фабриках

По мотивам:

Коротко. Ещё о фабриках

Я там писал - "фабрики, скажем так - это "полиморфизм в квадрате"".

Так вот.

Я сегодня сделал "полиморфизм в кубе".

Как?

Сделал "фабрику фабрик".

Примерно так:

type
 TSomeDataToDecide = record
  ...
 end;//TSomeDataToDecide

 TUsedBaseClass = class abstract (TObject)
  public
   constructor Create(const aSomeDataToDecide: TSomeDataToDecide);
 end;//TUsedBaseClass

 RUsedBaseClass = class of TUsedBaseClass;

 TUsedImpl1 = class(TBaseClass)
 end;//TUsedImpl1

 TUsedImpl2 = class(TBaseClass)
 end;//TUsedImpl2

 TBaseClass = class abstract (TObject)
  private
   f_Used : TUsedBaseClass;
  public
   constructor Create(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide);
 end;//TBaseClass

 TImpl1 = class(TBaseClass)
 end;//TImpl1

 TImpl2 = class(TBaseClass)
 end;//TImpl2

 TBaseClassFactory = class abstract (TObject)
  public
   class function Make(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide): TBaseClass; virtual; abstract;
 end;//TBaseClassFactory

 RBaseClassFactory = class of TBaseClassFactory;

 TFactory1 = class(TBaseClassFactory)
  public
   class function Make(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide): TBaseClass; override;
 end;//TFactory1

 TFactory2 = class(TBaseClassFactory)
  public
   class function Make(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide): TBaseClass; override;
 end;//TFactory2

 TBaseClassFactoryFactory = class abstract (TObject)
  public
   class function Make(const aSomeDataToDecide: TSomeDataToDecide): RBaseClassFactory; virtual; abstract;
   class function Used(const aSomeDataToDecide: TSomeDataToDecide): RUsedBaseClass; virtual; abstract;
 end;//TBaseClassFactoryFactory

 RBaseClassFactoryFactory = class of TBaseClassFactoryFactory;

 TFactoryFactory1 = class (TObject)
  public
   class function Make(const aSomeDataToDecide: TSomeDataToDecide): RBaseClassFactory; override;
 end;//T1FactoryFactory1

 TFactoryFactory2 = class (TObject)
  public
   class function Make(const aSomeDataToDecide: TSomeDataToDecide): RBaseClassFactory; override;
 end;//T1FactoryFactory2

...

constructor TBaseClass.Create(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide);
begin
 f_Used := aUsed.Create(aSomeDataToDecide);
 ...
end;

...
 
class function TFactory1.Make(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide): TBaseClass;
begin
 if SomeCondition(aSomeDataToDecide) then
  Result := TImpl1.Create(aUsed, aSomeDataToDecide)
 else
 if SomeOtherCondition(aSomeDataToDecide) then
  Result := TImpl2.Create(aUsed, aSomeDataToDecide)
 else
 begin
  Assert(false);
  Result := nil;
 end;
end;

class function TFactory2.Make(aUsed: RUsedBaseClass; const aSomeDataToDecide: TSomeDataToDecide): TBaseClass;
begin
 if SomeCondition(aSomeDataToDecide) then
  Result := TImpl2.Create(aUsed, aSomeDataToDecide)
 else
 if SomeOtherCondition(aSomeDataToDecide) then
  Result := TImpl1.Create(aUsed, aSomeDataToDecide)
 else
 begin
  Assert(false);
  Result := nil;
 end;
end;

...

class function TFactoryFactory1.Make(const aSomeDataToDecide: TSomeDataToDecide): RBaseClassFactory;
begin
 if SomeCondition(aSomeDataToDecide) then
  Result := TFactory1
 else
 if SomeOtherCondition(aSomeDataToDecide) then
  Result := TFactory2
 else
 begin
  Assert(false);
  Result := nil;
 end;
end;

...

class function TFactoryFactory2.Make(const aSomeDataToDecide: TSomeDataToDecide): RBaseClassFactory;
begin
 if SomeCondition(aSomeDataToDecide) then
  Result := TFactory2
 else
 if SomeOtherCondition(aSomeDataToDecide) then
  Result := TFactory1
 else
 begin
  Assert(false);
  Result := nil;
 end;
end;

...
var
 l_FF : RBaseClassFactoryFactory;
 l_BC : TBaseClass;
 l_SD : TSomeDataToDecide;
begin
 ...
 l_SD := TSomeDataToDecide.Create(SomeParams);
 ...
 if SomeCondition(l_SD) then
  l_FF := TFactoryFactory1
 else
 if SomeOtherCondition(l_SD) then
  l_FF := TFactoryFactory2
 else
 begin
  Assert(false);
  l_FF := nil;
 end;
 l_BC := l_FF.Make(l_SD).Make(l_FF.Used(l_SD), l_SD);
 try
  ...
 finally
  FreeAndNil(l_BC):
 end;//try..finally
end;

Зачем всё это? Чтобы охватить "Це из Эн по Ка".

Для меня лично - всё вокруг реализации IStorage вертится.

Там есть блоки "такой системы" и блоки "другой системы". А ещё есть "блоки в заголовком" и "блоки без заголовка". А ещё есть блоки "такого размера" и есть "блоки другого размера".

Вот там и возникает "Це из Эн по Ка". Которая решается "фабриками фабрик".

Может быть кому-нибудь мысль понравится.

P.S. Понятно, что тут всё "не так линейно". Конечно в реале появляются "циклы" и "списки фабрик". Особенно там где написано SomeConditionXXX.

Могу и про это детально написать. Если вдруг интересно.

Реальный пример (а не "коня в вакууме") - я тоже постараюсь описать.

Но пока может быть кому-то и "конь в вакууме" понравится.

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

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