Programovanie

Navrhovanie oblastí a metód

Splátka tohto mesiaca Dizajnové techniky je druhý v minisérii stĺpcov o navrhovaní objektov. V stĺpci z minulého mesiaca, ktorý sa zaoberal návrhom objektov na správnu inicializáciu, som hovoril o tom, ako navrhnúť konštruktory a inicializátory. Tento mesiac a budúci mesiac prediskutujem princípy návrhu pre skutočné polia a metódy triedy. Potom budem písať o finalizátoroch a ukážem, ako navrhovať objekty na správne vyčistenie na konci ich životnosti.

Materiál pre tento článok (vyhýbanie sa špeciálnym údajovým hodnotám, použitie konštánt, minimalizácia väzby) a nasledujúci článok (maximalizácia súdržnosti) môžu byť mnohým čitateľom známe, pretože tento materiál je založený na všeobecných princípoch návrhu, ktoré sú celkom nezávislé od programovacieho jazyka Java. . Napriek tomu, pretože som sa za tie roky stretol s toľkými kódmi, ktoré tieto princípy nevyužívajú, myslím si, že si zaslúžia občasné preformulovanie. Okrem toho sa v tomto článku pokúšam ukázať, ako sa tieto všeobecné zásady uplatňujú najmä v jazyku Java.

Navrhovanie polí

Pri navrhovaní polí je hlavným pravidlom vyhnúť sa použitiu jednej premennej na reprezentáciu viacerých atribútov triedy. Toto pravidlo môžete porušiť tým, že v premennej uvediete špeciálne hodnoty, z ktorých každá má svoj osobitný význam.

Ako sa tu používa, atribút je rozlišovacia charakteristika objektu alebo triedy. Dva atribúty a Šálka ​​kávy objekt môže byť napríklad:

  • Množstvo kávy, ktoré šálka obsahuje
  • Či je pohár čistý alebo špinavý

Ak sa chcete podrobnejšie pozrieť na toto pravidlo, predstavte si, že navrhujete a Šálka ​​kávy triedy pre virtuálnu kaviareň opísanú v minulom mesiaci Dizajnové techniky stĺpec. Predpokladajme, že chcete modelovať, či šálka kávy vo vašej virtuálnej kaviarni bola alebo nebola umytá a je pripravená na použitie ďalším zákazníkom. Vďaka týmto informáciám budete mať istotu, že šálku kávy nebudete znova používať, kým nebude umytá.

Ak sa rozhodnete, že vám záleží iba na tom, či je alebo nie je pohár vypraný, ak je prázdny, môžete použiť osobitnú hodnotu vnútorná káva pole, ktoré sa zvyčajne používa na sledovanie množstva kávy v šálke, na vyjadrenie neumytej šálky. Ak je 473 mililitrov (16 uncí) maximálne množstvo kávy v najväčšej šálke, potom maximálna hodnota vnútorná káva normálne by bolo 473. Môžete teda použiť an vnútorná káva hodnota povedzme 500 (špeciálna hodnota) na označenie prázdneho pohára, ktorý je neumytý:

// V zdrojovom pakete v súborových poliach / ex1 / CoffeeCup.java trieda CoffeeCup {private int innerCoffee; public boolean isReadyForNextUse () {// Ak šálka kávy nie je umývaná, potom // nie je pripravená na ďalšie použitie if (innerCoffee == 500) {return false; } návrat pravdivý; } public void setCustomerDone () {innerCoffee = 500; // ...} public void wash () {innerCoffee = 0; // ...} // ...} 

Tento kód dá Šálka ​​kávy namieta požadované správanie. Problém s týmto prístupom spočíva v tom, že špeciálne hodnoty nie sú ľahko pochopiteľné a kód sa tak ťažšie mení. Aj keď v komentári popíšete špeciálne hodnoty, ďalším programátorom môže trvať dlhšie, kým pochopia, čo váš kód robí. Okrem toho váš kód nemusí nikdy pochopiť. Môžu vašu triedu používať nesprávne alebo ju môžu zmeniť tak, že zavedú chybu.

Napríklad, ak niekto neskôr pridá 20 uncí šálky do ponuky virtuálnej kaviarne, bolo by možné do šálky umiestniť až 592 mililitrov (ml) kávy. Ak programátor pridá novú veľkosť šálky bez toho, aby zistil, že používate 500 ml, aby ste naznačili, že je potrebné šálku umyť, je pravdepodobné, že dôjde k chybe. Ak by si zákazník vo vašej virtuálnej kaviarni kúpil šálku s objemom 20 uncí, potom by si dal veľký dúšok s objemom 92 ml, potom by mu v šálke zostalo presne 500 ml. Zákazník by bol šokovaný a nespokojný, keď po vypití iba 92 ml pohár zmizol z jeho ruky a objavil sa v umývadle pripravený na umývanie. A aj keby si programátor, ktorý uskutočňoval zmenu, uvedomil, že používate špeciálnu hodnotu, pre nevypratý atribút bude potrebné zvoliť inú špeciálnu hodnotu.

Lepší prístup k tejto situácii je mať samostatné pole na modelovanie samostatného atribútu:

// V zdrojovom pakete v súborových poliach / ex2 / CoffeeCup.java trieda CoffeeCup {private int innerCoffee; súkromné ​​booleovské potrebyPranie; public boolean isReadyForNextUse () {// Ak šálka kávy nie je umývaná, potom // nie je pripravená na ďalšie použitie return! needsWashing; } public void setCustomerDone () {needsWashing = true; // ...} public void wash () {needsWashing = false; // ...} // ...} 

Tu vnútorná káva pole sa používa iba na modelovanie množstva kávy v atribúte šálka. Atribút cup-needs-washing je vymodelovaný podľa potreby Umývanie lúka. Táto schéma je ľahšie pochopiteľná ako predchádzajúca schéma, ktorá používala špeciálnu hodnotu vnútorná káva a nebránilo by by niekomu v rozšírení maximálnej hodnoty pre vnútorná káva.

Používanie konštánt

Ďalším pravidlom, ktoré treba dodržiavať pri vytváraní polí, je použitie konštant (statické konečné premenné) pre konštantné hodnoty, ktoré sa odovzdávajú, vracajú z alebo používajú v rámci metód. Ak metóda očakáva v jednom zo svojich parametrov jednu z konečnej množiny konštantných hodnôt, definovanie konštánt pomôže klientskym programátorom objasniť, čo je potrebné v tomto parametri odovzdať. Rovnako, ak metóda vracia jednu z konečných množín hodnôt, deklarovanie konštánt robí programátorom klientov zrejmejším, čo môžu od výstupu očakávať. Napríklad je ľahšie pochopiť toto:

if (cup.getSize () == CoffeeCup.TALL) {} 

než je to pochopiť:

if (cup.getSize () == 1) {} 

Mali by ste tiež definovať konštanty pre vnútorné použitie metódami triedy - aj keď sa tieto konštanty nepoužívajú mimo triedy - sú tak ľahšie pochopiteľné a dajú sa zmeniť. Použitie konštánt robí kód flexibilnejším. Ak si uvedomíte, že ste nesprávne vypočítali hodnotu a nepoužili ste konštantu, budete musieť prejsť svojím kódom a zmeniť každý výskyt pevne zakódovanej hodnoty. Ak ste predsa použili konštantu, budete ju musieť zmeniť iba tam, kde je definovaná ako konštanta.

Konštanty a kompilátor Java

Je užitočné vedieť o kompilátore Java, že so statickými konečnými poliami (konštantami) zaobchádza inak ako s inými druhmi polí. Odkazy na statické konečné premenné inicializované na konštantu kompilácie sú vyriešené v čase kompilácie na lokálnu kópiu konštantnej hodnoty. To platí pre konštanty všetkých primitívnych typov a typu java.lang.String.

Keď sa vaša trieda zvyčajne odvoláva na inú triedu, povedzte to java.lang.Math - kompilátor Java umiestňuje symbolické odkazy na triedu Matematika do súboru triedy pre vašu triedu. Napríklad ak vyvolá metóda vašej triedy Math.sin (), váš súbor triedy bude obsahovať dva symbolické odkazy na Matematika:

  • Jeden symbolický odkaz na triedu Matematika
  • Jeden symbolický odkaz na Matematikaje hriech () metóda

Vykonať kód obsiahnutý vo vašej triede, na ktorý sa odkazuje Math.sin (), JVM by potrebovalo načítať triedu Matematika vyriešiť symbolické odkazy.

Ak váš kód na druhej strane odkazoval iba na statickú premennú konečnej triedy PI vyhlásený v triede Matematika, na kompilátor Java nebude umiestnený žiadny symbolický odkaz Matematika v súbore triedy pre vašu triedu. Namiesto toho by jednoducho umiestnilo kópiu doslovnej hodnoty Math.PI do súboru triedy svojej triedy. Vykonať kód obsiahnutý vo vašej triede, ktorá používa Math.PI konštanta, JVM by nemusel načítať triedu Matematika.

Výsledkom tejto funkcie kompilátora Java je, že JVM nemusí pracovať o toľko ťažšie, aby používal konštanty, ako to robí s použitím literálov. Preferovanie konštánt pred literálmi je jedným z mála návrhových pokynov, ktoré zvyšujú flexibilitu programu bez rizika akejkoľvek degradácie výkonu programu.

Tri druhy metód

Zvyšok tohto článku sa bude zaoberať technikami návrhu metódy, ktoré sa zaoberajú údajmi, ktoré metóda používa alebo upravuje. V tejto súvislosti by som rád identifikoval a pomenoval tri základné typy metód v programoch Java: úžitková metóda the metóda stavového pohľadua metóda zmeny stavu.

Úžitková metóda

Úžitková metóda je metóda triedy, ktorá nepoužíva ani nemení stav (premenné triedy) svojej triedy. Tento druh metódy jednoducho poskytuje užitočnú službu súvisiacu s jej triedou objektov.

Niektoré príklady úžitkových metód z rozhrania Java API sú:

  • (V triede Celé číslo) public static int toString (int i) - vráti nový String objekt predstavujúci zadané celé číslo v radix 10
  • (V triede Matematika) verejný statický natívny dvojitý cos (dvojitý a) - vráti trigonometrický kosínus uhla

Metóda stavového pohľadu

Metóda štátneho zobrazenia je metóda triedy alebo inštancie, ktorá vracia určitý pohľad na vnútorný stav triedy alebo objektu bez zmeny tohto stavu. (Tento druh metódy bezohľadne ignoruje Heisenbergov princíp neurčitosti - pozrite si Zdroje, ak potrebujete aktualizáciu tohto princípu.) Metóda štátneho zobrazenia môže jednoducho vrátiť hodnotu premennej triedy alebo inštancie alebo môže vrátiť hodnotu vypočítanú z niekoľko premenných triedy alebo inštancie.

Niektoré príklady metód zobrazenia stavu z rozhrania Java API sú:

  • (V triede Objekt) public String toString () - vráti reťazcovú reprezentáciu objektu
  • (V triede Celé číslo) verejný bajt byteValue () - vráti hodnotu Celé číslo objekt ako bajt
  • (V triede String) public int indexOf (int ch) - vráti index v rámci reťazca prvého výskytu zadaného znaku

Metóda zmeny stavu

Metóda zmeny stavu je metóda, ktorá môže transformovať stav triedy, v ktorej je metóda deklarovaná, alebo ak ide o inštančnú metódu, objekt, na ktorý je vyvolaná. Keď je vyvolaná metóda zmeny stavu, predstavuje to „udalosť“ pre triedu alebo objekt. Kód metódy „spracováva“ udalosť, čo môže potenciálne zmeniť stav triedy alebo objektu.

Niektoré príklady metód zmeny stavu z rozhrania Java API sú:

  • (V triede StringBuffer) verejný doplnok StringBuffer (int i) - pripojí reťazcové znázornenie int argument k StringBuffer
  • (V triede Hashtable) public synchronized void clear () - vymaže Hashtable takže neobsahuje žiadne kľúče
  • (V triede Vektor) verejná konečná synchronizovaná void addElement (Object obj) - pridá zadaný komponent na koniec súboru Vektor, čím sa jeho veľkosť zväčšila o jednu

Minimalizácia spojenia metód

Vyzbrojení týmito definíciami metód užitočnosti, stavu a zmien stavu ste pripravení na diskusiu o prepojení metód.

Pri navrhovaní metód by jedným z vašich cieľov mala byť minimalizácia spojka - miera vzájomnej závislosti medzi metódou a jej prostredím (iné metódy, objekty a triedy). Čím menej prepojenia existuje medzi metódou a jej prostredím, tým je táto metóda nezávislejšia a flexibilnejšia je jej koncepcia.

Metódy ako transformátory údajov

Aby sme porozumeli spojeniu, pomáha nám myslieť si metódy čisto ako transformátory údajov. Metódy prijímajú údaje ako vstup, vykonávajú operácie s týmito údajmi a generujú údaje ako výstup. Stupeň väzby metódy je určený predovšetkým tým, odkiaľ získava svoje vstupné údaje a kam dáva svoje výstupné údaje.

Obrázok 1 zobrazuje grafické znázornenie metódy ako dátového transformátora: Schéma toku údajov zo štruktúrovaného (nie objektovo orientovaného) návrhu.

Vstup a výstup

Metóda v jazyku Java môže získať vstupné údaje z mnohých zdrojov:

  • Môže vyžadovať, aby volajúci pri vyvolaní špecifikoval svoje vstupné údaje ako parametre
  • Môže získavať údaje z akýchkoľvek premenných prístupnej triedy, ako sú napríklad vlastné premenné triedy alebo akékoľvek prístupné premenné triedy inej triedy.
  • Ak ide o inštančnú metódu, môže zachytiť inštančné premenné z objektu, na ktorý bola vyvolaná

Metóda môže rovnako vyjadrovať svoj výstup na mnohých miestach:

  • Môže vrátiť hodnotu, buď primitívny typ, alebo referenciu na objekt
  • Môže meniť objekty, na ktoré odkazujú odkazy odovzdané ako parametre
  • Môže meniť akékoľvek premenné triedy svojej vlastnej triedy alebo akékoľvek prístupné premenné triedy inej triedy
  • Ak ide o inštančnú metódu, môže zmeniť akékoľvek inštančné premenné objektu, na ktorý bola vyvolaná
  • Môže to spôsobiť výnimku

Upozorňujeme, že parametre, návratové hodnoty a vyvolané výnimky nie sú jedinými druhmi vstupov a výstupov metód uvedených v zoznamoch vyššie. S premennými inštancie a triedy sa tiež zaobchádza ako so vstupom a výstupom. Z objektovo orientovaného pohľadu sa to môže javiť ako neintuitívne, pretože prístup k premenným inštancií a tried v Jave je „automatický“ (metóde nemusíte nič výslovne odovzdávať). Pri pokuse o odhad spojenia metódy však musíte skontrolovať druh a množstvo údajov použitých a upravených kódom bez ohľadu na to, či bol prístup kódu k týmto údajom „automatický“ alebo nie.

Minimálne spojené úžitkové metódy

Najmenej spojená metóda, ktorá je v Jave možná, je metóda obslužného programu, ktorá:

  1. Berie vstup iba z jeho parametrov
  2. Vyjadruje svoj výstup iba prostredníctvom svojich parametrov alebo návratovej hodnoty (alebo zrušením výnimky)
  3. Prijíma ako vstup iba údaje, ktoré metóda skutočne potrebuje
  4. Vráti ako výstup iba údaje, ktoré sú skutočne vyrobené metódou

Dobrá úžitková metóda

Napríklad metóda convertOzToMl () zobrazené nižšie akceptuje int ako jediný vstup a vráti znak int ako jediný výstup:

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