Programování

Vnitřní třídy

Otázka: K čemu jsou tedy vnitřní třídy dobré?

A: Vnitřní třídy vnořeny do jiných tříd. Normální třída je přímý člen balíčku, třída nejvyšší úrovně. Vnitřní třídy, které byly k dispozici v prostředí Java 1.1, přicházejí ve čtyřech příchutích:

  • Statické třídy členů
  • Třídy členů
  • Místní třídy
  • Anonymní třídy

Pojďme se na každou z nich rychle podívat.

Stručně, a statická třída členů je statickým členem třídy. Stejně jako jakákoli jiná statická metoda má statická členská třída přístup ke všem statickým metodám nadřazené nebo nejvyšší třídy.

Jako statická členská třída, a členská třída je také definován jako člen třídy. Na rozdíl od statické odrůdy je členská třída specifická pro instanci a má přístup ke všem metodám a členům, dokonce i nadřazeným tento odkaz.

Místní třídy jsou deklarovány v rámci bloku kódu a jsou viditelné pouze v tomto bloku, stejně jako jakákoli jiná proměnná metody.

Nakonec an anonymní třída je místní třída, která nemá žádné jméno.

Abych odpověděl na vaši konkrétní otázku, zaměřím se na členské a anonymní vnitřní třídy, protože s těmi se pravděpodobně setkáte a používáte je. Pro mě lze výhody vnitřních tříd rozdělit do tří kategorií: objektově orientovaná výhoda, organizační výhoda a výhoda zpětného volání.

Objektově orientovaná výhoda

Podle mého skromného názoru je nejdůležitější vlastností vnitřní třídy to, že vám umožňuje přeměnit věci na objekty, které byste za normálních okolností nezměnili. To umožňuje, aby byl váš kód ještě více objektově orientovaný, než by byl bez vnitřních tříd.

Podívejme se na třídu členů. Vzhledem k tomu, že jeho instance je členem nadřazené instance, má přístup ke všem členům a metodám v nadřazené instanci. Na první pohled se to nemusí zdát moc; tento druh přístupu již máme v rámci metody v nadřazené třídě. Třída člena nám však umožňuje vzít logiku z rodiče a objektivizovat ji. Například třída stromu může mít metodu a mnoho pomocných metod, které provádějí prohledávání nebo procházení stromu. Z objektově orientovaného hlediska je strom strom, nikoli vyhledávací algoritmus. K provedení hledání však potřebujete důkladnou znalost datových struktur stromu.

Vnitřní třída nám umožňuje odstranit tuto logiku a umístit ji do vlastní třídy. Takže z objektově orientovaného hlediska jsme odstranili funkčnost z místa, kam nepatří, a vložili jsme ji do své vlastní třídy. Díky použití vnitřní třídy jsme úspěšně oddělili vyhledávací algoritmus od stromu. Nyní, abychom změnili vyhledávací algoritmus, můžeme jednoduše vyměnit novou třídu. Mohl bych pokračovat, ale to otevírá náš kód mnoha výhodám poskytovaným objektově orientovanými technikami.

Organizační výhoda

Objektově orientovaný design není věcí každého, ale vnitřní třídy naštěstí poskytují více. Z organizačního hlediska nám vnitřní třídy umožňují dále organizovat naši strukturu balíčků pomocí jmenných prostorů. Místo toho, aby se vše skládalo do plochého balíčku, mohou být třídy dále vnořeny do tříd. Explicitně, bez vnitřních tříd, jsme byli omezeni na následující hierarchickou strukturu:

balíček1 třída 1 třída 2 ... třída n ... balíček n 

S vnitřními třídami můžeme dělat následující:

balíček 1 třída 1 třída 2 třída 1 třída 2 ... třída n 

Při pečlivém používání mohou vnitřní třídy poskytnout strukturální hierarchii, která přirozeně zapadá do vašich tříd.

Výhoda zpětného volání

Vnitřní členské třídy i anonymní třídy poskytují pohodlnou metodu pro definování zpětných volání. Nejviditelnější příklad se týká kódu GUI. Aplikace zpětného volání se však může rozšířit na mnoho domén.

Většina Java GUI má nějaký druh komponenty, která podněcuje actionPerformed () volání metody. Většina vývojářů má bohužel implementaci svého hlavního okna ActionListener. Výsledkem je, že všechny komponenty sdílejí stejné actionPerformed () metoda. Abychom zjistili, která složka akci provedla, je obvykle obrovský, ošklivý přepínač actionPerformed () metoda.

Zde je příklad monolitické implementace:

veřejná třída SomeGUI rozšiřuje JFrame implementuje ActionListener {chráněné tlačítko JButton1; chráněné tlačítko JButton2; ... chráněné tlačítko JButtonN; public void actionPerformed (ActionEvent e) {if (e.getSource () == button1) {// udělat něco} else if (e.getSource () == button2) {... získáte obrázek 

Kdykoli uvidíte spínače nebo velké -li/pokud jinde bloky, ve vaší mysli by vám měly začít zvonit hlasité poplašné zvony. Obecně jsou takové konstrukce špatným objektově orientovaným designem, protože změna v jedné části kódu může vyžadovat odpovídající změnu v příkazu switch. Třídy vnitřních členů a anonymní třídy nám umožňují dostat se pryč od změněných actionPerformed () metoda.

Místo toho můžeme definovat vnitřní třídu, která se implementuje ActionListener pro každou komponentu, které chceme poslouchat. To může vést k mnoha vnitřním třídám. Můžeme se však vyhnout velkým příkazům switchů a máme další bonus zapouzdření naší logiky akcí. Tento přístup navíc může zlepšit výkon. V přepínači, kde jsou n můžeme očekávat n / 2 srovnání v průměrném případě. Vnitřní třídy nám umožňují nastavit korespondenci 1: 1 mezi umělcem akce a posluchačem akcí. Ve velkém grafickém uživatelském rozhraní mohou takové optimalizace podstatně ovlivnit výkon. Anonymní přístup může vypadat takto:

public class SomeGUI extends JFrame {... button member declarations ... protected void buildGUI () {button1 = new JButton (); button2 = new JButton (); ... button1.addActionListener (new java.awt.event.ActionListener () {public void actionPerformed (java.awt.event.ActionEvent e) {// něco udělat}}); .. opakujte pro každé tlačítko 

Použitím vnitřních tříd členů by stejný program vypadal takto:

public class SomeGUI extends JFrame {... button member declarations // internal class definitions class Button1Handler implements ActionListener {public void actionPerformed (ActionEvent e) {// do something}} ... definovat vnitřní členskou třídu pro každé tlačítko chráněné void buildGUI () {// inicializovat tlačítka button1 = new JButton (); button2 = new JButton (); ... // zaregistrovat instanci posluchače akcí vnitřní třídy // pro každé tlačítko button1.addActionListener (new Button1Handler ()); .. opakujte pro každé tlačítko 

Vzhledem k tomu, že vnitřní třídy mají přístup ke všemu v mateřské společnosti, můžeme přesunout jakoukoli logiku, která by se objevila v monolitu actionPerformed () implementace do vnitřní třídy.

Raději používám členské třídy jako zpětná volání. To je však otázka osobních preferencí. Cítím, že příliš mnoho anonymních tříd nepořádek kód. Mám také pocit, že anonymní třídy se mohou stát nepraktickými, pokud jsou větší než jeden nebo dva řádky.

Nevýhody?

Stejně jako cokoli jiného, ​​musíte brát dobré se špatným. Vnitřní třídy mají své nevýhody. Z hlediska údržby může být pro nezkušené vývojáře prostředí Java obtížné pochopit vnitřní třídu. Použití vnitřních tříd také zvýší celkový počet tříd ve vašem kódu. Kromě toho z hlediska vývoje většina nástrojů Java přichází s trochou podpory v oblasti vnitřních tříd. Například pro své každodenní kódování používám IBM VisualAge for Java. Zatímco vnitřní třídy se budou kompilovat v rámci VisualAge, neexistuje žádný prohlížeč nebo šablona vnitřní třídy. Místo toho musíte jednoduše zadat vnitřní třídu přímo do definice třídy. To bohužel ztěžuje procházení vnitřní třídy. Je také obtížné psát, protože při psaní do definice třídy nebo použití vnitřní třídy ztratíte mnoho pomůcek pro dokončení kódu VisualAge.

Tony Sintes je senior konzultant v ObjectWave se specializací na telekomunikace. Sintes, programátor prostředí Java 1.1 a vývojář prostředí Java 2, pracoval v prostředí Java od roku 1997.

Další informace o tomto tématu

  • „Specifikace vnitřních tříd“ od společnosti Sun poskytuje podrobný pohled na vnitřní třídy

    //java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html

Tento příběh, „Vnitřní třídy“, původně publikoval JavaWorld.

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