Inleiding tot het null-objectpatroon

1. Overzicht

In deze korte tutorial bekijken we het null-objectpatroon, een speciaal geval van het strategiepatroon. We zullen het doel ervan beschrijven en wanneer we zouden moeten overwegen om het te gebruiken.

Zoals gewoonlijk zullen we ook een eenvoudig codevoorbeeld geven.

2. Null-objectpatroon

In de meeste objectgeoriënteerde programmeertalen mogen we geen nul referentie. Daarom worden we vaak gedwongen om te schrijven nul controleert:

Commando cmd = getCommand (); if (cmd! = null) {cmd.execute (); }

Soms, als het aantal van dergelijke als uitspraken hoog worden, kan de code lelijk, moeilijk te lezen en foutgevoelig worden. Dit is wanneer het null-objectpatroon van pas kan komen.

De bedoeling van het null-objectpatroon is om dat soort nul controleren. In plaats daarvan kunnen we het nulgedrag identificeren en het inkapselen in het type dat door de clientcode wordt verwacht. Vaker wel dan niet, is zo'n neutrale logica heel eenvoudig: niets doen. Op deze manier hebben we niet langer te maken met speciale afhandeling van nul referenties.

We kunnen null-objecten gewoon op dezelfde manier behandelen als elk ander exemplaar van een bepaald type dat eigenlijk wat meer geavanceerde bedrijfslogica bevat. Bijgevolg blijft de klantcode schoner.

Omdat null-objecten geen status zouden moeten hebben, is het niet nodig om meerdere keren identieke instanties te maken. Dus we zullen vaak implementeren null-objecten als eenlingen.

3. Het UML-diagram van een nulobjectpatroon

Laten we het patroon visueel bekijken:

Zoals we kunnen zien, kunnen we de volgende deelnemers identificeren:

  • Cliënt vereist een exemplaar van AbstractObject
  • AbstractObject definieert het contract Cliënt verwacht - het kan ook gedeelde logica bevatten voor de implementatieklassen
  • RealObject werktuigen AbstractObject en biedt echt gedrag
  • NullObject werktuigen AbstractObject en biedt neutraal gedrag

4. Implementatie

Nu we een duidelijk idee hebben van de theorie, laten we eens kijken naar een voorbeeld.

Stel je voor dat we een berichtroutertoepassing hebben. Aan elk bericht moet een geldige prioriteit worden toegewezen. Ons systeem moet berichten met hoge prioriteit naar een sms-gateway sturen, terwijl berichten met gemiddelde prioriteit naar een JMS-wachtrij moeten worden gerouteerd.

Van tijd tot tijd, Er kunnen echter berichten met "ongedefinieerde" of lege prioriteit komen op onze applicatie. Dergelijke berichten moeten worden weggegooid voor verdere verwerking.

Eerst maken we het Router koppel:

openbare interface Router {ongeldige route (bericht msg); }

Laten we vervolgens twee implementaties van de bovenstaande interface maken - degene die verantwoordelijk is voor routering naar een sms-gateway en degene die de berichten naar de JMS-wachtrij stuurt:

public class SmsRouter implementeert router {@Override public void route (Message msg) {// implementatiedetails}}
public class JmsRouter implementeert router {@Override public void route (Message msg) {// implementatiedetails}}

Tenslotte, laten we ons null-object implementeren:

public class NullRouter implementeert router {@Override public void route (Message msg) {// niets doen}}

We zijn nu klaar om alle stukjes samen te voegen. Laten we eens kijken hoe de voorbeeldclientcode eruit kan zien:

openbare klasse RoutingHandler {openbare ongeldige handle (herhaalde berichten) {voor (Bericht msg: berichten) {Router router = RouterFactory.getRouterForMessage (msg); router.route (msg); }}}

Zoals we kunnen zien, we behandelen allemaal Router objecten op dezelfde manier, ongeacht welke implementatie wordt geretourneerd door de RouterFactory. Hierdoor kunnen we onze code schoon en leesbaar houden.

5. Wanneer moet u het null-objectpatroon gebruiken?

We zouden het Null-objectpatroon moeten gebruiken als een Cliënt zou anders controleren nul gewoon om de uitvoering over te slaan of een standaardactie uit te voeren. In dergelijke gevallen kunnen we de neutrale logica inkapselen in een null-object en dat terugsturen naar de client in plaats van de nul waarde. Op deze manier hoeft de code van de klant niet langer op de hoogte te zijn van een bepaalde instantie nul of niet.

Een dergelijke benadering volgt algemene objectgeoriënteerde principes, zoals Tell-Don't-Ask.

Om beter te begrijpen wanneer we het null-objectpatroon moeten gebruiken, stellen we ons voor dat we het moeten implementeren Klantdelta interface als volgt gedefinieerd:

openbare interface Customerbao {Collectie findByNameAndLastname (String naam, String achternaam); Klant getById (lange id); }

De meeste ontwikkelaars zouden dat doen terugkeer Collections.emptyList () van findByNameAndLastname () in het geval dat geen van de klanten overeenkomt de opgegeven zoekcriteria. Dit is een heel goed voorbeeld van het volgen van het null-objectpatroon.

In tegenstelling daarmee is de krijgenById () moet de klant retourneren met het opgegeven ID. Iemand die deze methode aanroept, verwacht de specifieke klantentiteit te krijgen. Als een dergelijke klant niet bestaat, moeten we deze expliciet retourneren nul om aan te geven dat er iets mis is met de opgegeven id.

Zoals bij alle andere patronen, we moeten onze specifieke use case in overweging nemen voordat we blindelings het null-objectpatroon implementeren. Anders kunnen we onbedoeld enkele bugs in onze code introduceren die moeilijk te vinden zijn.

6. Conclusie

In dit artikel hebben we geleerd wat het null-objectpatroon is en wanneer we het mogen gebruiken. We hebben ook een eenvoudig voorbeeld van het ontwerppatroon geïmplementeerd.

Zoals gewoonlijk zijn alle codevoorbeelden beschikbaar op GitHub.