Bagian 10. Menyamakan Perkalian

$5 + Rp 10=Rp 9.010 jika $1=Rp 9000

Rp 10 * 2 = Rp 20

Efek perkalian terhadap object?

Amount harus private?

Pembulatan uang?

Equals()

GetHashCode()

Jenis object?

Null?

$10*2=$20

Duplikasi dolar dan rupiah

Equality yang lebih umum

Method Times() yang lebih umum

Bedakan dollar dan rupiah

Currency?

Hapus test DollarMultiplication

Di bagian 9 kita telah tahu bahwa untuk menghilangkan duplikasi class Rupiah dan Dollar kita harus mengidentikkan method Times(). Sebelum melakukan itu, mari kita lihat lagi bentuk method Times() dimasing-masing class.

public class Rupiah:Money{
	public override Money Times(int multiplier){
		return Money.Rp(this.m_amount *multiplier);
	}
}
public class Dollar:Money{
	public override Money Times(int multiplier){
		return Money.US(this.m_amount *multiplier);
	}
}

Hanya tinggal factory method sajalah yang membuat kedua method ini tidak identik. Yang satu menggunakan Money.Rp dan yang satunya lagi menggunakan Money.US.

Adakah terlihat sebuah cara yang cukup jelas agar keduanya identik? Tidak ada. Bagaimana kalau kita balikin lagi ke bentuk pemanggilan konstruktor langsung? Hah, bukannya barusan kita ganti! Duh, yakin gak sih TDD bisa memberikan solusi. Kok kesannya bolak-balik dan muter. Mulai frustrasi ya. Kalau kamu pernah memainkan game puzzle kamu pasti tahu kalau yang suka bolak-balik itu bukan hanya TDD. Sabar ya, jangan frustrasi, kita balikin lagi.

public class Rupiah:Money{
	public override Money Times(int multiplier){
		return new Rupiah(this.m_amount *multiplier, “Rp”);
	}
}
public class Dollar:Money{
	public override Money Times(int multiplier){
		return new Dollar(this.m_amount *multiplier, “US”);
	}
}

Saya jalankan test dan tidak ada pesan kesalahan. Jadi kita akan tetap maju.

Kita tahu bahwa state m_currency tidak pernah berubah, karena memang kita buat seperti itu. Bagaimana kalau konstanta “Rp” dan “US” kita ganti dengan m_currency? Seharusnya tidak menjadi masalah. Daripada sibuk memakai otak atau malah menghitung kancing baju, lebih bagus kita tanya langsung saja ke komputer. Caranya? Ubah saja code-nya,

public class Rupiah:Money{
	public override Money Times(int multiplier){
		return new Rupiah(this.m_amount *multiplier, m_currency);
	}
}
public class Dollar:Money{
	public override Money Times(int multiplier){
		return new Dollar(this.m_amount *multiplier, m_currency);
	}
}

Saya jalankan test dan tidak ada pesan kesalahan. Maju terus!

Tinggal sedikit lagi. Bagaimana kalau kita ganti saja Rupiah dan Dollar dengan Money, sehingga method Times() akan menjadi,

public class Rupiah:Money{
	public override Money Times(int multiplier){
		return new Money(this.m_amount *multiplier, m_currency);
	}
}
public class Dollar:Money{
	public override Money Times(int multiplier){
		return new Money(this.m_amount *multiplier, m_currency);
	}
}

Bukankah money itu abstract! Tidak mengapa kita coba saja.

Saya jalankan test. Benar dugaanmu Money itu abstract, tidak bisa diinstance, begitu kurang lebih pesan kompile. So? Ya sudah kita buang abstract-nya dan kita definisikan method Times() dan property
Currency yang tadinya abstract juga.

public  class Money{
	...
	public virtual Money Times(int multiplier){
		return null;
	}
	public virtual string Currency {
		get {
			return "";
		}
	}
}

note: dalam C#/mono agar method induk bisa dioverride oleh turunannya harus kita definisikan abastrak atau virtual.

Saya jalankan test dan kali ini gagal. Hore…akhirnya ketemu merah juga. Merah karena apa nih? Kesalahan terjadi di dua tempat, test Multiplication dan test DollarMultiplication. Pesan kesalahannya berbunyi, class yang seharusnya keluar adalah Rupiah tapi yang muncul Money dan pesan class yang seharusnya keluar adalah Dollar tapi yang muncul malah Money.

Masalahnya ada disini, method Equality. Tempat kedua object dibandingkan.

public  class Money{ 

	public override bool Equals(object obj){
		Money money=(Money)obj;
		return this.m_amount==money.m_amount &&
			this.GetType().Equals(money.GetType());
	}
}

Kita membandingkan tipe class bukan currency dari object. Jadi harus kita ubah? Betul. Tetapi tidak sekarang. Kalau kita rubah sekarang berarti kita merubah kode asli tanpa test. Dan itu sangat dilarang. Jadi kita harus membuat test baru? Benar. Tetapi kita harus ubah dulu yang merah tadi agar menjadi green kembali. Karena kita dilarang dalam sebuah test bersamaan ada dua case yang merah. Bikin frustasi bukan? Tidak apa-apa. Ini namanya bekerja dengan hati-hati. Pasang pelampungmu.

public class Rupiah:Money{
	public override Money Times(int multiplier){
		return new Rupiah(this.m_amount *multiplier, m_currency);
	}
}
public class Dollar:Money{
	public override Money Times(int multiplier){
		return new Dollar(this.m_amount *multiplier, m_currency);
	}
}

Test saya jalankan dan green. Sekarang siap menambahkan test baru.

[Test]
public void DifferentClassEquality(){
	Assert.AreEqual(new Money(10,"Rp"),new Rupiah(10,"Rp"));
}

Test ini gagal seperti yang diharapkan. Untuk membuat test ini green, kita harus membandingkan currency bukan tipe class.

public  class Money{ 

	public override bool Equals(object obj){
		Money money=(Money)obj;
		return this.m_amount==money.m_amount &&
			this.m_currency.Equals(money.m_currency);
	}
}

Setelah diubah seperti ini, test menjadi green.

Ok. Sekarang kita kembali lagi ke method Times(). Konstruktor Rupiah kembali kita ganti dengan Money. (Emang strika, bolak balik).

public class Rupiah:Money{
	public override Money Times(int multiplier){
		return new Money(this.m_amount *multiplier, m_currency);
	}
}

Test saya jalankan dan green. Hore!! Go on…
Dengan cara yang sama kita terapkan pada Dollar.

public class Dollar:Money{
	public override Money Times(int multiplier){
		return new Money(this.m_amount *multiplier, m_currency);
	}
}

Test saya jalankan dan green. Hore!! Bagus bagus…

Nah, kedua method ini sekarang nampak persis sama. Karena itu lebih baik kita taruh di class Money agar tidak ada duplikasi. Saya hapus method di dua tempat dan saya pindahkan ke class Money. Demikian juga dengan property Currency. Karena tidak memerlukan lagi mengoverride method Times(), maka kata virtual saya hilangkan. Dan inilah class Money.

public  class Money{
	protected string m_currency;
	protected int m_amount;
	public Money(int amount, string currency){
		this.m_amount=amount;
		this.m_currency=currency;
	}
	public override bool Equals(object obj){
		Money money=(Money)obj;
		return this.m_amount==money.m_amount &&
			this.m_currency.Equals(money.m_currency);
	}
	public static Money Rp(int amount){
		return new Rupiah(amount,"Rp");
	}
	public static Money US(int amount){
		return new Dollar(amount,"US");
	}
	public Money Times(int multiplier){
		return new Money(this.m_amount *multiplier, m_currency);;
	}
	public string Currency {
		get {
			return this.m_currency;
		}
	}
}

Dan kita berhak mencoret “Method Times() yang lebih umum” dari daftar.

<!– @page { size: 8.5in 11in; margin: 0.79in } TD P { margin-bottom: 0in } P { margin-bottom: 0.08in } –>

$5 + Rp 10=Rp 9.010 jika $1=Rp 9000

Rp 10 * 2 = Rp 20

Efek perkalian terhadap object?

Amount harus private?

Pembulatan uang?

Equals()

GetHashCode()

Jenis object?

Null?

$10*2=$20

Duplikasi dolar dan rupiah

Equality yang lebih umum

Method Times() yang lebih umum

Bedakan dollar dan rupiah

Currency?

Hapus test DollarMultiplication

Iklan

Satu Tanggapan

  1. Setelah baca dari bagian 1-10, akhirnya bisa pulang dengan membawa sedikit pencerahan tentang konsep TDD (padahal sebenarnya karena dah kelaparan, soalnya hampir jam 6 sore), walau bentar lagi bakalan lupa. Tapi setidaknya ada tambahan referensi, jadi bisa nyontek klo dikasih tugas heheh. Dari 6 siklus TDD, dapat dikompres menjadi 3 yaitu buat test (dgn menghayalkan proses bisnis dari interface), buat test berjalan (kebut secepat mungkin walau melanggar aturan software engineering ck..ck..ck..), dan yang terakhir bertobatlah dan kembali ke aturan software engineering.

    Nah sekarang, mari pulang (kabur…!!)

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: