Inversion of Control Container met interfaces

Geschreven door: op maandag 29 juni 2020

Leestijd:

In vorige blogitems schreef ik over interfaces en hoe ze ervoor zorgen dat je software beter te testen is en hoe ze helpen bij het uitbreiden van je software. Een andere voordeel van interfaces is dat ze je kunnen helpen bij het onderhouden van je software. Dat kan enerzijds door via het contract af te dwingen hoe een object, als implementatie van een bepaalde interface, dient te werken en anderzijds doordat je gedwongen wordt je implementaties te definiëren en het is logisch dat in sommige gevallen op een slimme plek te doen. IFileSystem is hier een goed voorbeeld: het zal niet voorkomen (of bij hoge uitzondering) dat je in je software meer dan één implementatie hiervan gebruikt. Tijdens het testen zal je weliswaar een specifieke implementatie gebruiken, maar je daadwerkelijke applicatie maakt gebruik van je lokale schijven óf van een Cloud-oplossing, maar niet van beide. Het is dus verstandig de initialisatie van deze implementatie in je software zo snel en globaal mogelijk te doen.

Bijvoorbeeld, ik zou al mijn implementaties kunnen initialiseren in een aparte functie die ik meteen aanroep:

    private static IFileSystem fileSystem;

    static void Main(string[] args)
    {
        InitClasses();

        // Doe hier dingen.

        storeReview(review, fileSystem);
    }

    private static void InitClasses()
    {
        fileSystem = new ActualFileSystem();
    }

Waarschijnlijk gebruik je hiervoor dan een aparte klasse, maar het idee is hetzelfde: je geeft op één plek aan welke implemenatie gebruikt wordt voor IFileSystem en andere interfaces. Wil je er één aanpassen of iets toevoegen, zoals een bepaalde configuratie, dan doe je dat in InitClasses.

In .NET (en andere programmeeromgevingen) kan je gebruikmaken van een Inversion of Control Container om zoveel mogelijk van deze logica voor je te regelen. Je geeft dan meestal alleen aan welke implementatie je wilt hebben voor welke interface en op veel plekken kan je deze implementatie gewoon ophalen via de container, terwijl je het maar op één plek hebt gedefinieerd. In .NET Core kan je hier bijvoorbeeld Unity Container voor gebruiken.

Eerst plaats ik de review-code in een aparte klasse:

static void Main(string[] args)
{
    InitClasses();

    var reviewApp = new ReviewApp(fileSystem);

    reviewApp.StoreReviews();
}

//...

public ReviewApp(IFileSystem fileSystem)
{
    this.fileSystem = fileSystem;
}

Als ik dit uitvoer, dan werkt het zoals het al deed. Om Unity Container te gebruiken moet ik enkele aanpassingen doen:

private static UnityContainer iocContainer;

static void Main(string[] args)
{
    InitClasses();

    var reviewApp = iocContainer.Resolve<ReviewApp>();

    reviewApp.StoreReviews();
}

private static void InitClasses()
{
    iocContainer = new UnityContainer();
    iocContainer.RegisterType<IFileSystem, ActualFileSystem>();
}

In bovenstaande voorbeeld laat ik iocContainer alles regelen. De container ziet dat ReviewApp een IFileSystem verwacht in de constructor en zoekt op welke ik heb ingesteld en geeft deze mee. Als ik nou een tweede argument verwacht (INetworkHandler bijvoorbeeld), dan hoef ik de initialisatie maar op 2 plekken aan te passen:

public ReviewApp(IFileSystem fileSystem, INetworkHandler networkHandler)
// ...
private static void InitClasses()
    //...
    iocContainer.RegisterType<IFileSystem, ActualFileSystem>();
    iocContainer.RegisterType<INetworkHandler, MyNetworkHandler>();

De container "weet" dat mijn constructor een INetworkHandler verwacht en zoekt op welke ik heb ingesteld. Door op zo min mogelijk plekken aanpassingen te doen, heb ik de software minder complex gemaakt en gemakkelijker te onderhouden. In bovenstaande voorbeeld voegt de IoC Container niet bepaald veel waarde toe. Er zijn echter meer voordelen en het zorgt er ook voor dat je gedwongen wordt je code logischer in elkaar te zetten. Zie voor meer informatie ook: http://unitycontainer.org/articles/introduction.html.


Andere blogartikelen

Bel 072 5345 888
Meer dan 40 bedrijven vertrouwen op ons
Allrig is de alles in een leverancier binnen de energie-industrie
AOC is een toonaangevend wereldwijd bedrijf actief in de verkoop van kwaliteitsharsen
ERIKS is een toonaangevende en innovatieve leverancier aan de procesindustrie en aan machinebouwers, die zowel de rol van specialist als die van brede MRO-leverancier vervult
Industrieel dienstverlener Heinen & Hopman Engineering uit Bunschoten is dé wereldwijde specialist op het gebied van klimaatbeheersing
Handicare is een internationale organisatie die ouderen helpt om hun dagelijks leven gemakkelijker te maken door het produceren van hoogwaardige trapliften
Op de hoogte blijven?

Meld u aan voor de gratis nieuwsbrief om op de hoogte te blijven van onze activiteiten