TDD_I_08: Tvorba objektů

$5 + 10 CHF = $10 je-li kurz 2:1

$5 * 2 = $10

Převést položku mnozstvi na soukromou

Vedlejší účinky třídy Dolar?

Zaokrouhlování peněz?

Metoda equals()

Metoda hashCode()

Rovnost s null

Rovnost objektů

5 CHF * 2 = 10 CHF

Dolar / Frank duplicita

Společná metoda equals()

Společné násobení

Porovnání franků a dolarů

Obě implementace metody krat() jsou si nápadně podobné:

Frank

	Frank krat(int nasobek) {
		return new Frank(mnozstvi * nasobek);
	}

Dolar

	Dolar krat(int nasobek) {
		return new Dolar(mnozstvi * nasobek);
	}

Můžeme pokročit k jejich sjednocení tím, že obě budou vracet objekt Penize.

Frank

	Penize krat(int nasobek) {
		return new Frank(mnozstvi * nasobek);
	}

Dolar

	Penize krat(int nasobek) {
		return new Frank(mnozstvi * nasobek);
	}

Další krok už není tak snadný. Obě podtřídy Penize nemají tolik úkolů, aby stálo za to se jimi zabývat a tak bychom se jich rádi zbavili. To však nelze udělat v jediném velkém kroku, protože bychom si tak nemohli názorně předvést TDD.

Tak dobře. čím méně přímých odkazů na obě podtřídy bude existovat, tím blíže budeme k jejich odstranění. Ve třídě Penize můžeme zavést tovární metodu, která vrací objekt Dolar. Použili bychom ji takto:

	public void testNasobeni() {
		Dolar pet = Penize.dolar(5);
		assertEquals(new Dolar(10), pet.krat(2));
		assertEquals(new Dolar(15), pet.krat(3));
	}

Iplementace vytváří a vrací objekt Dolar:

Penize

	static Dolar dolar(int mnozstvi) {
		return new Dolar(mnozstvi);
	}

My však chceme, aby reference na objekty Dolar zmizely. Proto musíme v testu změnit deklaraci:

	public void testNasobeni() {
		Penize pet = Penize.dolar(5);
		assertEquals(new Dolar(10), pet.krat(2));
		assertEquals(new Dolar(15), pet.krat(3));
	}

Překladač nás úslužně informuje, že metoda krat() není ve třídě Penize definována. V tomto okamžiku jěště nejsme připraveni ji implementovat a proto musí být třída Penize abstraktní (myslím, že tím jsme měli začít) a deklarovat metodu Penize.krat():

Penize

abstract class Penize {
	abstract Penize krat(int nasobek);
}

Teď můžeme změnit deklaraci tovární metody:

Penize

	static Penize dolar(int mnozstvi) {
		return new Dolar(mnozstvi);
	}

Všechny testy fungují, takže jsme alespoň nic nepokazili. Nyní můžeme použít naši tovární metodu všude v testech:

	public void testNasobeni() {
		Dolar pet = Penize.dolar(5);
		assertEquals(Penize.dolar(10), pet.krat(2));
		assertEquals(Penize.dolar(15), pet.krat(3));
	}

	public void testRovnosti() {
		assertTrue(Penize.dolar(5).equals(Penize.dolar(5)));
		assertFalse(Penize.dolar(5).equals(Penize.dolar(6)));
		assertTrue(new Frank(5).equals(new Frank(5)));
		assertFalse(new Frank(5).equals(new Frank(6)));
		ssertFalse(new Frank(5).equals(Penize.dolar(5)));
	}

Teď jsme na tom trochu lépe než předtím. Žádný klientský kód neví, že existuje podtřída nazvaná Dolar Jelikož jsme oddělili testy od podtříd, můžeme nyní volně měnit dědičnost, aniž by to mělo nějaký vliv na výkonný kód.

Než však začneme slepě měnit test testNasobeniFranku, všimenem si, že netestuje žádnou logiku, která by nebyla testována testem pro násobení v objektu Dolar. Pokud smažeme tento test, ztratíme snad důvěru ve výsledný kód? jen trochu, a tak ho tam necháme. Ale je to podezřelé.

	public void testRovnosti() {
		assertTrue(Penize.dolar(5).equals(Penize.dolar(5)));
		assertFalse(Penize.dolar(5).equals(Penize.dolar(6)));
		assertTrue(Penize.frank(5).equals(Penize.frank(5)));
		assertFalse(Penize.frank(5).equals(Penize.frank(6)));
		ssertFalse(Penize.frank(5).equals(Penize.dolar(5)));
	}

	public void testNasobeniFranku() {
		Penize pet = Penize.frank(5);
		assertEquals(Penize.frank(10), pet.krat(2));
		assertEquals(Penize.frank(15), pet.krat(3));
	}

Implementace je stejná jako v případě metody Penize.dolar():

Penize

	static Penize frank(int mnozstvi) {
		return new Frank(mnozstvi);
	}

$5 + 10 CHF = $10 je-li kurz 2:1

$5 * 2 = $10

Převést položku mnozstvi na soukromou

Vedlejší účinky třídy Dolar?

Zaokrouhlování peněz?

Metoda equals()

Metoda hashCode()

Rovnost s null

Rovnost objektů

5 CHF * 2 = 10 CHF

Dolar / Frank duplicita

Společná metoda equals()

Společné násobení

Porovnání franků a dolarů

Měna?

Smazat metodu testNasobeniFranku?

Dále se zbavíme duplicity v metodě krat(). Abychom si to zopakovali:

Vývoj řízený testy, Kapitola 7 | Dr3dweRkZ | Vývoj řízený testy, Kapitola 9