Site icon Patrick Schiefer

Using the “Template method pattern” in AL

In this blogpost I continue my series of design patterns for AL.

This time I write about a simple pattern which could make the readability of your code much better. I’m talking about the “Template method pattern”. The pattern defines the skeleton of a process without implenting it. The real implemenation is handelt in another codeunit.

The big advantage of this pattern is that it helps us to solve similar problems with a similar solution


In AL you need at least 3 objects to implement the pattern:

The template codeunit

The template codeunit defines the skeleton of a solution without implementation. In the following example I’m implementing a data export

codeunit 50000 ExportTemplate
{
    procedure ExportData(export: Interface IDataExport)
    begin
        if not export.CheckData() then
            exit;
        if export.GetLinesToExport() then begin
            repeat
                export.ExportLine();
            until not export.NextLine();
        end;
        export.finish();
    end;
}

The interface

Now that we have the skeleton we need the interface which is used in the codeunit above

interface IDataExport
{
    procedure CheckData(): Boolean;
    procedure GetLinesToExport(): Boolean;
    procedure ExportLine();
    procedure NextLine(): Boolean;
    procedure Finish();
}

That’s the whole and simple pattern, just to have a complet sample I add one implentation for the pattern

Implementation Example

Here is the implementation of the interface

codeunit 50001 SalesHeaderExport implements IDataExport
{
    procedure SetSalesHeader(DocType: Enum "Sales Document Type"; No: Code[10])
    begin
        SalesHeader.Get(DocType, No);
    end;

    procedure CheckData(): Boolean
    begin
        SalesHeader.TestField(Status, Enum::"Sales Document Status"::Released);
    end;

    procedure GetLinesToExport(): Boolean
    begin
        SalesLines.SetRange("Document Type", SalesHeader."Document Type");
        SalesLines.SetRange("Document No.", SalesHeader."No.");
        exit(SalesLines.FindSet());
    end;

    procedure ExportLine()
    begin
        //Generate Exportdata here
    end;

    procedure NextLine(): Boolean
    begin
        exit(SalesLines.Next() > 0);
    end;

    procedure Finish()
    begin
        // Send or Save data here
    end;

    var
        SalesHeader: Record "Sales Header";
        SalesLines: Record "Sales Line";

}

And here is the usage

codeunit 50002 ExportOrders
{
    procedure ExportOrder(DocType: Enum "Sales Document Type"; No: Code[10])
    var
        export: Codeunit ExportTemplate;
        exportImpl: Codeunit SalesHeaderExport;
        exportInt: Interface IDataExport;
    begin
        exportImpl.SetSalesHeader(DocType, No);
        exportInt := exportImpl;
        export.ExportData(exportInt);
    end;
}
Exit mobile version