JE_19: Nahrazujte struktury třídami

Konstrukce struct jazyka C byla z programovacího jazyka Java vypuštěna, protože třída dokáže všechno, co struktura a ještě něco navíc. Struktura pouze seskupuje více datových atributů do jediného objektu; třída asociuje operace s výsledným objektem a umož�uje skrýt datové atributy před uživateli daného objektu. Jinými slovy, třída dokáže zapouzdřit svá data do objektu, k němuž přistupuje výhradně prostřednictvím jeho metod, čímž dovoluje implementátorovi její návrh časem změnit (rada 12).

Při prvním vystavení jazyku Java někteří programátoři v jazyce C věří, že třídy jsou jako náhrada struktur za určitých okolností příliš komplikované (těžkotonážní), tak tomu však není. Degenerované třdy skládající se výhradně z datových atributů přibližně odpovídají strukturám jazyka C:

// Degenerované třídy, jako je tato, nesmějí být veřejné!
class Point {
	public float x;
	public float y;
}

Protože se k takovým třídám přistupuje jejich datovými atributy, neposkytují výhody zapouzdření. Nemůžete změnit reprezentaci takové třídy bez změny jejího API, nemůžete si vynutit žádné invarianty a nemůžete ani vykonat nějakou akci, deojde-li ke změně určitého atributu. Zatvrzelí objektově orientovaní programátoři mají pocit, že takové třídy jsou prokletím, které by mělo být nahrazeno třídami se soukromými atributy a veřejnými přístupovými metodami:

// Třída se zapouzdřenou strukturou
class Point {
	private float x;
	private float y;

	public Point(float x, float y) {
		this.x = x;
		this.y = y;
	}

	public float getX()  {
		return x;
	}

	public float getY() {
		return y;
	}

	public void setX(float x) {
		this.x = x;
	}

	public void setY(float y) {
		this.y = y;
	}
}

Zatvrzelci mají nepochybně pravdu, pokud se jedná o veřejné třídy: Je-li nějaká třída přístupná mimo hranice svého balíčku, pak opatrný programátor poskytne přístupové metody, aby si zachoval možnost změnit interní reprezentaci dané třídy. Kdyby měla veřejná třída vystavovat své datové atributy, pak nebude vůbec možné její reprezentaci změnit, jelikož klientský kód veřejných tříd může být distribuován po celém známém vesmíru.

Je-li však třída přátelská nebo je-li soukromou vnořenou třídou, pak není samo o sobě nic špatného na přímém vystavování jejích datových atributů - pokud tedy opravdu popisují abstrakci zajišťovanou danou třídou. Tento přístup vytváří méně vizuálního zmatku než princip s přístupovou metodou, jak v definici dané třídy, tak i v klientském kódu, jenž tuto třídu využívá. Třebaže je klientský kód svázán s interní reprezentací takové třídy, tento kód jen omezen na balíček obsahující danou třídu. Pokud nastane ta nepravděpodobná situace, že bude zapotřebí změnit reprezentaci, pak je možné vykonat takovou změnu, která nebude mít žádný vliv na kód mimo balíček. V případě soukromé vnořené třídy se rozsah změny dále omezuje jen na obklopující třídu.

Několik tříd v knihovnách platformy Java narušuje doporučení, že veřejné třídy by neměly vystavovat své atributy. Mezi nejvýraznější patří Point a Dimension v balíčku java.awt. Nesnažte se tyto třídy napodobovat - měly by vám sloužit jako varovné příklady. Jak je vysvětleno v radě 37, rozhodnutí vystavit vnitřní součásti třídy Dimension mělo za následek vážný problém s výkonností, který nebylo možné vyřešit, aniž by nedošlo k ovlivnění klientů.