воскресенье, 21 апреля 2013 г.

Фабричный метод

Вот тут был достаточно развесистый пост про подсчёт ссылок - http://18delphi.blogspot.com/2013/04/iunknown.html

Хочу обратить внимание на следующий кусок:

 TmyReferenceCountGuard = class(TmyInterfacedObject, ImyReferenceCountGuard)
  {* Класс исключительно для примеров }
...
public
 // public methods
   class function Make: ImyReferenceCountGuard; reintroduce;
     {* Фабрика TmyReferenceCountGuard.Make }
 end;//TmyReferenceCountGuard
....
 
class function TmyReferenceCountGuard.Make: ImyReferenceCountGuard;
var
 l_Inst : TmyReferenceCountGuard;
begin
 l_Inst := Create;
 try
  Result := l_Inst;
 finally
  l_Inst.Free;
 end;//try..finally
end;


И его использование:
procedure TmyReferenceCountGuardTest.DoIt;
var
 l_G : ImyReferenceCountGuard;
begin
 l_G := TmyReferenceCountGuard.Make;
...


Вне зависимости от того как реализован подсчёт ссылок - я предпочитаю пользоваться ИМЕННО фабричным методом, а не конструктором. Во-первых - его использование подчёркивает тот факт, что конструируется ИМЕННО интерфейс, а не просто объект. А во-вторых - снимается опасность использования конструктора при передаче интерфейса внутрь метода с параметром const (то что описал gunsmoker тут - http://www.gunsmoker.ru/2013/04/plugins-9.html (Неочевидная особенность учёта ссылок интерфейсов (конструктор в const-параметре))).

Да и читать мне такое приятнее/проще. А при "моём подсчёте ссылок" - ещё и скрывается лишний Free (внутрь фабричного метода).

Ну и понятное дело, что можно сделать несколько фабричных методов - для создания одним классом разных интерфейсов. И например с overload по параметрам.

Да и кеширование в фабричный метод всегда можно потом безболезненно воткнуть, или логирование, ну или бизнес-логику какую. Или например граничные условия обработать.

По мне - если бы это позволял корректно сделать компилятор - я бы вообще конструктор бы скрыл в данном конкретном случае. А так - "приходится договариваться с коллегами".

Следующим постом я надеюсь - доберусь до подсчёта ссылок и контейнеров.

(!)(!)(!) ДА в случае наследования от TInterfacedObject фабричный метод выглядит так:

class function TmyReferenceCountGuard.Make: ImyReferenceCountGuard;
begin
 Result := Create;
end;

3 комментария:

  1. Кстати если бы мне позволил компилятор сделать это корректно - я бы в данном случае - вообще бы спрятал бы конструктор.

    ОтветитьУдалить
    Ответы
    1. Эммм... А разве компилятор запрещает спрятать конструктор в protected?

      Удалить
  2. Компилятор не запрещает. Но при этом будет виден конструктор от TObject.
    Можете проверить.

    ОтветитьУдалить