Kennisbank

Spring4D factory pattern

Welke opties zijn er in het Spring4D framework die we niet kennen, maar die wel heel bruikbaar zijn? Nou, eigenlijk best veel. Eén van die dingen is het Factory Pattern. Het komt erg van pas als je het open/closed principe wilt toepassen. Je code wel open voor uitbreiding, maar gesloten voor aanpassing.

Een klassiek voorbeeld is het werken met enumeraties of getallen die een bepaalde status aangeven. Er ontstaan dan al snel allerlei conditionele structuren die aangepast moeten worden zodra er een nieuwe status of waarde bijkomt. In onderstaande voorbeeld wordt afhankelijk van een factuurstatus bepaalde code uitgevoerd. Voor het opsplitsen van de code is het factory pattern toegepast.

Dit is de definitie van de factuur en status:

type
  {$SCOPEDENUMS ON}
  TInvoiceStatus = (New, Sent, Overdue, Paid);
  {$SCOPEDENUMS OFF}

  TInvoice = class
  public
    function Status: TInvoiceStatus;
  end;
Om het factory pattern te gebruiken includen we de Spring.DesignPatterns unit.
Vervolgens definiëren we de factory. Die bestaat uit een key value en een functie waarmee je de methode teruggeeft die je uit wilt voeren. Dat klinkt complex, maar valt wel mee. In ons geval is de key value de factuurstatus (TInvoiceStatus). De functie die we uit willen voeren heeft een factuur (TInvoice) als parameter. De definitie voor de factory ziet er dan zo uit:
type
  TProcessInvoiceProc = reference to procedure(const Invoice: TInvoice);

  TInvoiceProcessor = class
  private
    FFactory: TFactory<TInvoiceStatus, TProcessInvoiceProc >;
    procedure InitialiseFactory;
  end;

procedure TInvoiceProcessor .InitialiseFactory;
begin
  FFactory := TFactory<TInvoiceStatus, TProcessInvoiceProc >.Create;

  FFactory.RegisterFactoryMethod(TInvoiceStatus.New, ProcessInvoiceNew);
  FFactory.RegisterFactoryMethod(TInvoiceStatus.Sent, ProcessInvoiceSent);
  FFactory.RegisterFactoryMethod(TInvoiceStatus.Overdue, ProcessInvoiceOverdue);
  FFactory.RegisterFactoryMethod(TInvoiceStatus.Paid, ProcessInvoicePaid);
end;
In bovenstaande code is al te zien hoe de factory aangemaakt en geïnitialiseerd wordt. Aan iedere status is een “Process” functie gekoppeld. Deze functie geeft de definitie van de TProcessInvoiceProc terug, om de code voor die status uit te kunnen voeren. Dat definieer je als volgt:
function TInvoiceProcessor .ProcessInvoiceNew: TProcessInvoiceProc;
begin
  Result := procedure(const Invoice: TInvoice)
            begin
              ShowMessage('This is a new invoice');
            end
end;

Het toepassen van de factory is dan eenvoudig en gaat zoals zichtbaar in onderstaande code:

procedure TInvoiceProcessor .ProcessInvoice(const Invoice: TInvoice);
begin
  if FFactory.IsRegistered(Invoice.Status) then
  begin
    var Process := FFactory.GetInstance(Invoice.Status;)
    Process(Invoice);
  end;
end;
Op deze manier is met behulp van het factory pattern je code eenvoudig te splitsen en te verbeteren.

Geschreven door Kees de Kraker
Directeur

Contact

Laat ons helpen jouw ambities concreet te maken.