Abstraktné triedy v Jave

1. Prehľad

Existuje veľa prípadov pri implementácii zmluvy, keď chceme odložiť niektoré časti implementácie, aby sa dokončili neskôr. Môžeme to ľahko dosiahnuť v Jave prostredníctvom abstraktných tried.

V tomto tutoriáli sa dozvieme základy abstraktných tried v Jave a v akých prípadoch môžu byť užitočné.

2. Kľúčové koncepty pre abstraktné triedy

Predtým, ako sa ponoríte do abstraktnej triedy, pozrime sa na ich najrelevantnejšie vlastnosti:

  • Definujeme abstraktnú triedu pomocou abstraktné modifikátor predchádzajúci trieda kľúčové slovo
  • Abstraktnú triedu je možné zaradiť do podtriedy, ale nemožno ju vytvoriť inštanciou
  • Ak trieda definuje jeden alebo viac abstraktné metód, potom musí byť deklarovaná samotná trieda abstraktné
  • Abstraktná trieda môže deklarovať abstraktné aj konkrétne metódy
  • Podtrieda odvodená z abstraktnej triedy musí buď implementovať všetky abstraktné metódy základnej triedy, alebo musí byť sama abstraktná

Pre lepšie pochopenie týchto pojmov si vytvoríme jednoduchý príklad.

Nechajme našu základnú abstraktnú triedu definovať abstraktné API stolovej hry:

public abstract class BoardGame {// ... deklarácie polí, konštruktory public abstract void play (); // ... konkrétne metódy}

Potom môžeme vytvoriť podtriedu, ktorá implementuje hrať metóda:

public class Checkers rozširuje BoardGame {public void play () {// ... implementácia}}

3. Kedy použiť abstraktné triedy

Teraz, poďme analyzovať niekoľko typických scenárov, kde by sme mali uprednostňovať abstraktné triedy pred rozhraniami a triedy betónu:

  • Chceme zapuzdriť niektoré bežné funkcie na jednom mieste (opätovné použitie kódu), ktoré bude zdieľať viac súvisiacich podtried
  • Musíme čiastočne definovať API, ktoré môžu naše podtriedy ľahko rozšíriť a vylepšiť
  • Podtriedy musia zdediť jednu alebo viac bežných metód alebo polí s chránenými modifikátormi prístupu

Nezabúdajme, že všetky tieto scenáre sú dobrým príkladom úplného dodržiavania princípu otvoreného / uzavretého na základe dedičstva.

Navyše, keďže použitie abstraktných tried implicitne narába so základnými typmi a podtypmi, využívame tiež výhody polymorfizmu.

Upozorňujeme, že opätovné použitie kódu je veľmi závažným dôvodom na použitie abstraktných tried, pokiaľ je v hierarchii tried zachovaný vzťah „je-a“.

A Java 8 pridáva ďalšie vrásky s predvolenými metódami, ktoré niekedy môžu nahradiť úplné vytvorenie abstraktnej triedy.

4. Ukážková hierarchia čítačiek súborov

Aby sme jasnejšie pochopili funkčnosť, ktorú abstraktné triedy prinášajú do tabuľky, pozrime sa na ďalší príklad.

4.1. Definovanie základnej abstraktnej triedy

Ak by sme teda chceli mať niekoľko typov čítačiek súborov, mohli by sme vytvoriť abstraktnú triedu, ktorá obsahuje to, čo je bežné pri čítaní súborov:

verejná abstraktná trieda BaseFileReader {chránená cesta filePath; chránený BaseFileReader (cesta filePath) {this.filePath = filePath; } verejná cesta getFilePath () {návrat filePath; } public List readFile () hodí IOException {návrat Files.lines (filePath) .map (this :: mapFileLine) .collect (Collectors.toList ()); } chránený abstraktný String mapFileLine (reťazcový riadok); }

Všimnite si, že sme to vytvorili cesta k súboru chránené, aby k nim mali podtriedy v prípade potreby prístup. Dolezitejsie, niečo sme nechali späť: ako vlastne analyzovať riadok textu z obsahu súboru.

Náš plán je jednoduchý: hoci naše konkrétne triedy nemajú špeciálny spôsob ukladania cesty k súboru alebo jeho prechádzania, každý z nich bude mať špeciálny spôsob transformácie každého riadku.

Na prvý pohľad, BaseFileReader sa môže zdať zbytočné. Je to však základ čistého, ľahko rozšíriteľného dizajnu. Od toho, môžeme ľahko implementovať rôzne verzie čítačky súborov, ktoré sa môžu sústrediť na ich jedinečnú obchodnú logiku.

4.2. Definovanie podtried

Prirodzená implementácia je pravdepodobne taká, ktorá prevádza obsah súboru na malé písmená:

public class LowercaseFileReader extends BaseFileReader {public LowercaseFileReader (Path filePath) {super (filePath); } @Override public String mapFileLine (reťazec) {return line.toLowerCase (); }}

Alebo môže byť iný, ktorý prevádza obsah súboru na veľké písmená:

public class UppercaseFileReader extends BaseFileReader {public UppercaseFileReader (Path filePath) {super (filePath); } @Override public String mapFileLine (reťazec) {return line.toUpperCase (); }}

Ako vidíme z tohto jednoduchého príkladu, každá podtrieda sa môže sústrediť na svoje jedinečné správanie bez potreby špecifikovať ďalšie aspekty čítania súborov.

4.3. Používanie podtriedy

A nakoniec, použitie triedy, ktorá dedí z abstraktnej, sa nijako nelíši od ktorejkoľvek inej konkrétnej triedy:

@Test public void givenLowercaseFileReaderInstance_whenCalledreadFile_thenCorrect () vyvolá výnimku {URL location = getClass (). GetClassLoader (). GetResource ("files / test.txt") Cesta cesty = Paths.get (location.toURI ()); BaseFileReader lowercaseFileReader = nový LowercaseFileReader (cesta); assertThat (lowercaseFileReader.readFile ()). isInstanceOf (List.class); }

Pre jednoduchosť je cieľový súbor umiestnený pod src / main / resources / files priečinok. Preto sme na získanie cesty k vzorovému súboru použili zavádzač aplikačnej triedy. Neváhajte a pozrite si náš návod na načítanie tried v jazyku Java.

5. Záver

V tomto rýchlom článku naučili sme sa základy abstraktných tried v Jave a kedy ich použiť na dosiahnutie abstrakcie a zapuzdrenie spoločnej implementácie na jednom mieste.

Ako obvykle sú všetky ukážky kódu zobrazené v tomto tutoriáli dostupné na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found