Constanten in Java: patronen en antipatronen

1. Inleiding

In dit artikel gaan we leren over het gebruik van constanten in Java met een focus op algemene patronen en antipatronen.

We beginnen met enkele basisconventies voor het definiëren van constanten. Van daaruit gaan we verder met algemene antipatronen voordat we eindigen met een blik op algemene patronen.

2. Basisprincipes

Een constante is een variabele waarvan de waarde niet verandert nadat deze is gedefinieerd.

Laten we eens kijken naar de basisprincipes voor het definiëren van een constante:

privé statische definitieve int OUR_CONSTANT = 1;

Sommige van de patronen die we zullen bekijken, hebben betrekking op de openbaar of privaat toegang modifier beslissing. We maken onze constanten statisch en laatste en geef ze een geschikt type, of dat nu een Java-primitief is, een klasse of een opsomming. De naam moet uit hoofdletters bestaan ​​en de woorden moeten worden gescheiden door onderstrepingstekens, ook wel bekend als schreeuwende slangenkoffer. Ten slotte bieden we de waarde zelf aan.

3. Anti-patronen

Laten we eerst beginnen met te leren wat we niet moeten doen. Laten we eens kijken naar een aantal algemene antipatronen die we kunnen tegenkomen bij het werken met Java-constanten.

3.1. Magische nummers

Magische getallen zijn numerieke literalen in een codeblok:

if (nummer == 3.14159265359) {// ...}

Ze zijn moeilijk te begrijpen voor andere ontwikkelaars. Als we in onze code een cijfer gebruiken, is het bovendien moeilijk om de waarde te wijzigen. We zouden in plaats daarvan het getal als een constante moeten definiëren.

3.2. Een grote klasse van wereldwijde constanten

Wanneer we een project starten, kan het natuurlijk aanvoelen om een ​​klasse met de naam te maken Constanten of Gebruikt met de bedoeling om alle constanten voor de toepassing daar te definiëren. Voor kleinere projecten is dit misschien oké, maar laten we eens kijken naar een aantal redenen waarom dit geen ideale oplossing is.

Laten we eerst eens voorstellen dat we honderd of meer constanten hebben allemaal in onze constantenklasse. Als de klasse niet wordt onderhouden, zowel om de documentatie bij te houden als om de constanten af ​​en toe in logische groepen te herstructureren, wordt het behoorlijk onleesbaar. We zouden zelfs kunnen eindigen met dubbele constanten met enigszins verschillende namen. Deze benadering geeft ons waarschijnlijk leesbaarheid en onderhoudsproblemen bij alles behalve de kleinste projecten.

Naast de logistiek van het onderhouden van de Constanten class zelf, nodigen we ook andere onderhoudbaarheidsproblemen uit door te veel onderlinge afhankelijkheid aan te moedigen met deze ene globale constantenklasse en verschillende andere delen van onze applicatie.

Op een meer technische kant, de Java-compiler plaatst de waarde van de constante in referentievariabelen in de klassen waarin we ze gebruiken. Dus als we een van onze constanten in onze constantenklasse wijzigen en alleen die klasse opnieuw compileren en niet de referentieklasse, kunnen we inconsistente constante waarden krijgen.

3.3. De constante interface-antipatroon

Het constante interfacepatroon is wanneer we een interface definiëren die alle constanten voor bepaalde functionaliteit bevat en vervolgens de klassen hebben die die functionaliteiten nodig hebben om de interface te implementeren.

Laten we een constante interface voor een rekenmachine definiëren:

openbare interface CalculatorConstants {dubbele PI = 3.14159265359; dubbele UPPER_LIMIT = 0x1.fffffffffffffP + 1023; opsomming Operatie {ADD, SUBTRACT, MULTIPLY, DIVIDE}; }

Vervolgens implementeren we onze Rekenmachine Constanten koppel:

public class GeometryCalculator implementeert CalculatorConstants {public doubleoperonTwoNumbers (double numberOne, double numberTwo, Operation operation) {// Code om een ​​operatie uit te voeren}}

Het eerste argument tegen het gebruik van een constante interface is dat het in strijd is met het doel van een interface. Het is de bedoeling dat we interfaces gebruiken om een ​​contract op te stellen voor het gedrag dat onze implementatieklassen gaan bieden. Wanneer we een interface vol constanten maken, definiëren we geen enkel gedrag.

Ten tweede stelt het gebruik van een constante interface ons open voor runtime-problemen die worden veroorzaakt door schaduwvorming in het veld. Laten we eens kijken hoe dat kan gebeuren door een te definiëren BOVENSTE LIMIET constant binnen ons GeometryCalculator klasse:

openbare statische laatste dubbele UPPER_LIMIT = 100000000000000000000.0;

Zodra we die constante definiëren in onze GeometryCalculator class, verbergen we de waarde in de Rekenmachine Constanten interface voor onze klas. We zouden dan onverwachte resultaten kunnen krijgen.

Een ander argument tegen dit antipatroon is dat het naamruimteverontreiniging veroorzaakt. Onze Rekenmachine Constanten zal nu in de naamruimte staan ​​voor al onze klassen die de interface implementeren, evenals voor hun subklassen.

4. Patronen

Eerder hebben we gekeken naar de juiste vorm om constanten te definiëren. Laten we eens kijken naar enkele andere goede praktijken voor het definiëren van constanten in onze applicaties.

4.1. Algemene goede praktijken

Als constanten logisch verband houden met een klasse, kunnen we ze daar gewoon definiëren. Als we een set constanten zien als leden van een opgesomd type, kunnen we een opsomming om ze te definiëren.

Laten we enkele constanten definiëren in a Rekenmachine klasse:

openbare klasse Calculator {openbare statische finale dubbele PI = 3.14159265359; privé statische laatste dubbele UPPER_LIMIT = 0x1.fffffffffffffP + 1023; openbare opsomming Operatie {ADD, SUBTRACT, DIVIDE, MULTIPLY} publieke dubbele operatorOnTwoNumbers (dubbel numberOne, double numberTwo, operatie operatie) {if (numberOne> UPPER_LIMIT) {throw new IllegalArgumentException ("'numberOne' is too large"); } if (numberTwo> UPPER_LIMIT) {throw new IllegalArgumentException ("'numberTwo' is te groot"); } dubbel antwoord = 0; switch (operatie) {case ADD: answer = numberOne + numberTwo; breken; case SUBTRACT: answer = numberOne - numberTwo; breken; case DIVIDE: answer = numberOne / numberTwo; breken; case MULTIPLY: answer = numberOne * numberTwo; breken; } antwoord terug; }}

In ons voorbeeld hebben we een constante gedefinieerd voor BOVENSTE LIMIET die we alleen van plan zijn te gebruiken in de Rekenmachine class, dus we hebben het ingesteld op privaat. We willen dat andere klassen kunnen gebruiken PI en de Operatie enum, dus we hebben die ingesteld op openbaar.

Laten we eens kijken naar enkele voordelen van het gebruik van een opsomming voor Operatie. Het eerste voordeel is dat het de mogelijke waarden beperkt. Stel je voor dat onze methode een string aanneemt voor de bewerkingswaarde met de verwachting dat een van de vier constante strings wordt geleverd. We kunnen gemakkelijk een scenario voorzien waarin een ontwikkelaar die de methode aanroept, zijn eigen stringwaarde verzendt. Met de opsommingzijn de waarden beperkt tot de waarden die we definiëren. We kunnen ook zien dat enums bijzonder goed geschikt zijn om in te gebruiken schakelaar verklaringen.

4.2. Constanten Klasse

Nu we enkele algemene goede praktijken hebben bekeken, gaan we eens kijken naar het geval waarin een constantenklasse een goed idee zou kunnen zijn. Laten we ons voorstellen dat onze applicatie een pakket klassen bevat die verschillende soorten wiskundige berekeningen moeten uitvoeren. In dit geval is het waarschijnlijk logisch dat we in dat pakket een constantenklasse definiëren voor constanten die we in onze berekeningsklassen zullen gebruiken.

Laten we een MathConstants klasse:

openbare laatste klasse MathConstants {openbare statische laatste dubbele PI = 3.14159265359; statische laatste dubbele GOLDEN_RATIO = 1.6180; statische laatste dubbele GRAVITATIONAL_ACCELERATION = 9,8; statische laatste dubbele EULERS_NUMBER = 2.7182818284590452353602874713527; openbare opsomming Bewerking {ADD, SUBTRACT, DIVIDE, MULTIPLY} private MathConstants () {}}

Het eerste dat we moeten opmerken, is dat onze klas is laatste om te voorkomen dat het wordt verlengd. Bovendien hebben we een privaat constructor, zodat het niet kan worden geïnstantieerd. Ten slotte kunnen we zien dat we de andere goede praktijken hebben toegepast die we eerder in het artikel hebben besproken. Onze constante PI is openbaar omdat we verwachten toegang nodig te hebben buiten ons pakket. De andere constanten die we hebben verlaten als pakket-privé, zodat we ze binnen ons pakket kunnen openen. We hebben al onze constanten gemaakt statisch en laatste en noemde ze in een schreeuwende slangenkoffer. De bewerkingen zijn een specifieke set waarden, dus we hebben een opsomming om ze te definiëren.

We kunnen zien dat onze specifieke constantenklasse op pakketniveau verschilt van een grote globale constantenklasse, omdat deze is gelokaliseerd in ons pakket en constanten bevat die relevant zijn voor de klassen van dat pakket.

5. Conclusie

In dit artikel hebben we de voor- en nadelen besproken van enkele van de meest populaire patronen en antipatronen die we tegenkomen bij het gebruik van constanten in Java. We begonnen met enkele basisregels voor opmaak, voordat we antipatronen behandelden. Nadat we een aantal veelvoorkomende antipatronen hadden leren kennen, hebben we gekeken naar patronen die we vaak op constanten zien.

Zoals altijd is de code beschikbaar op GitHub.