Er en switch-erklæring passende her, der tager en enum?
Der er en anden måde at undgå en switch
case, som bruger en Map
med en EnunMap
implementering, som vil beholde Type
som nøglen og værdien som Block
implementering.
Når du har at gøre med Enum
taster en EnumMap
implementering anbefales i henhold til Javadoc:
En specialiseret kortimplementering til brug med enum type nøgler.
Denne repræsentation er ekstremt kompakt og effektiv.
Implementeringsnote:Alle grundlæggende operationer udføres i konstant tid. De er sandsynligvis (dog ikke garanteret) hurtigere end deres HashMap-modstykker.
Eksempelkode ved brug af en EnumMap
i stedet for en switch
hvor nøglen er Type
enum-forekomst, og værdien er en Supplier<Block>
(en konstruktørreference):
//During initialization
Map<Type, Supplier<Block>> registry = new EnumMap<>(Type.class);
registry.put(Type.I, IBlock::new);
registry.put(Type.L, LBlock::new);
registry.put(Type.J, JBlock::new);
registry.put(Type.Z, ZBlock::new);
...
Så kan du hente den fra spawnBlock()
ved at angive den korrekte Type
og du ville få en ny forekomst af Block
implementering hver gang på grund af Supplier.get()
ring til sidst:
private void spawnBlock(Type type){
currentBlock = this.registry.get(type).get();
}
Switch er bedre end at bruge if-else-sætninger. Efter min mening er det meget renere kode. Bare sammenlign den med den samme kode ved at bruge if-else:
private void spawnBlock(Type type){
if(Type.I.equals(type)) {
currentBlock = new IBlock();
} else if(Type.L.equals(type)) {
currentBlock = new LBlock();
} else if(Type.J.equals(type)) {
currentBlock = new JBlock();
} else if(Type.Z.equals(type)) {
currentBlock = new ZBlock();
} else if(Type.S.equals(type)) {
currentBlock = new SBlock();
} else if(Type.T.equals(type)) {
currentBlock = new TBlock();
} else {
currentBlock = new OBlock();
}
}
Men ofte har du chancen for at bruge en anden tilgang end switch eller if-else. Bare tag et kig på de andre svar eller se på dette. Den forklarer, hvordan du kan forbedre din kode ved at bruge enum og sætte logikken direkte ind i enum.
Jeg er blevet bedt om at undgå at skifte udsagn, når det er muligt
Det er korrekt, men det du gør her måske være okay.
Pointen er:du ønsker ikke at have sådanne switch-udsagn over det hele . De er dårlige, fordi de kobler ting sammen. Og når du gentager det "samme" skiftemønster igen og igen, kan det blive til et vedligeholdelsesmareridt. Fordi ændringer i din enum-type ... betyder, at du bliver nødt til at se på hver switch for at afgøre, om den skal tilpasses.
Så når du er i stand til at skjule sådan skift fra det meste af din kode (ved kun at gøre det nogle få, ideelt set ét sted), er du okay.
Ikke desto mindre kunne en bedre tilgang være at erstatte hele denne switch-sætning med denne one-liner:
currentBlock = type.createBlock();
Med andre ord:hvorfor ikke lægge viden direkte ind i selve enum-klassen? Det har selvfølgelig andre implikationer, såsom en potentiel overtrædelse af enkelt ansvarsprincippet .
Men det føles ganske naturligt, at enummet, der angiver de forskellige typer af blokke, også giver et middel til at oprette sådanne blokke (i betragtning af at typen er den eneste information, der bestemmer, hvilken slags Block-underklasse du har brug for).
Og bemærk:du flytter dig ikke nødvendigvis kontakten ind i enummet. Du kan helt undgå at skifte her:
enum Type {
I(IBlock::new), L(LBlock::new), ...;
private Supplier<? extends Block> supplier;
private Type(Supplier<? extends Block> supplier) {
this.supplier = supplier;
}
public Block getBlock() {
return supplier.get();
}
(Jeg kørte ikke ovenstående gennem en compiler, så pas på med tastefejl )