En liten DSL för att beställa kaffe

Läste idag en trevlig artikel om att bygga egna DSL’er med C# och tänkte bolla idéerna med dig via bloggen. Observera att artikeln bara är fullständigt tillgänglig för prenumeranter (vilket jag är).

Artikeln gick ut på att visa en teknik för att skapa en intern DSL (inbyggd i språket) för att möjliggöra en ny syntax som är “enklare” att läsa för en ovan programmera, eller kanske bara för att göra det lite annorlunda.

Tekniken som används kallas för “member chaining” och går ut på att exponera egenskaper som returnerar inte den datatyp som egentligen förväntas utan istället en instans av det aktuella objektet som egenskapen finns på.

Ett exempel kan vara på sin plats i hur det skulle kunna se ut från början, i det förslaget att det handlar om att skapa ett objekt som är en beställning av en kaffe latte. Objektet skulle kunna tänkas se ut så här i en enkel form som använder automatiska egenskaper:

public class KaffeLatte

{

    public bool Dubbel { get; set; }

    public bool Vanilj { get; set; }

    public bool Fettfri { get; set; }

}

Och en beställning skulle kunna se ut som följande med hjälp av “object-initializers” i C#:

KaffeLatte latte = new KaffeLatte

{

    Dubbel = false,

    Fettfri = false,

    Vanilj = true

};

Ett alternativ som då beskrivs i artikeln är att istället skapa klassen på följande sätt:

public class KatteLatte

{

    public static KatteLatte beställ

    {

        get

        {

            return new KatteLatte();

        }

    }

 

    public KatteLatte dubbel

    {

        get

        {

            this.Dubbel = true;

            return this;

        }

    }

 

    public KatteLatte vanilj

    {

        get

        {

            this.Vanilj = true;

            return this;

        }

    }

 

    public KatteLatte fettfri

    {

        get

        {

            this.Vanilj = true;

            return this;

        }

    }

 

    public bool Vanilj { get; private set; }

    public bool Dubbel { get; private set; }

    public bool Fettfri { get; private set; }

}

Och då kan instansieringen istället skrivas på det här lite mer lättlästa sättet:

KatteLatte latte = KatteLatte.beställ

    .dubbel

    .fettfri

    .vanilj;

Skälet till att använda den statiska “factory-metoden” beställ är helt enkelt för att skapa själva instansen. Observera sedan också att flera av “get”-egenskaperna börjar med små bokstäver för att göra läsningen lite tydligare. I artikeln fortsätter sedan författaren att bygga reglerverk och nyttja både egenskaper och metoder, men det blir nog till för dig att köpa tidningen om du vill läsa vidare!

Jag tyckte att det var ett ganska snyggt sätt att försöka underlätta för läsaren, vad tycker du?