Konuyla ilgili önceki yazılar:
Para örneğimize kaldığımız yerden devam ediyoruz.
Yeni bir test yazalım.
- Var olan para üzerine yeni para ekleme
[Test]
public void YTL_VarOlanParayaYeniParaEkleme()
{
YTL ytl = new YTL(8);
ytl.Ekle(5);
Assert.AreEqual(ytl.Miktar, 13);
}
Resharper, Ekle metodunun olmadığını söylüyor.
public void Ekle(int ekMiktar)
{
miktar += ekMiktar;
}
Miktar alanını readonly yapmıştık.Bu durumda readonly özelliğini kaldırıyoruz.
Testimizi çalıştırdığımızda testi geçebildiğimizi görüyoruz.
Ekle metodunun aynısını Dolar sınıfı içerisine de yazıyoruz.Artık birşeyler gözümüze çarpmış olmalı.YTL ve Dolar sınıfının aynı özelliklere ve aynı metodlara sahip olduğunu görüyoruz.Öyleyse bu iki sınıfı ParaBase adında bir soyut sınıftan türetirsek ortak metodları tekrar yazmak zorunda kalmayız.
public abstract class ParaBase
{
protected int miktar;
protected ParaBase(int _miktar)
{
miktar = _miktar;
}
public int Miktar
{
get { return miktar; }
}
public bool AyniMi(ParaBase yeniYtl)
{
return Miktar == yeniYtl.Miktar;
}
public void Ekle(int ekMiktar)
{
miktar += ekMiktar;
}
}
public class YTL : ParaBase
{
public YTL(int _miktar) : base(_miktar)
{
}
}
public class Dolar:ParaBase
{
public Dolar(int _miktar) : base(_miktar)
{
}
}
Dolar ve YTL sınıfılarımız artık ParaBase soyut sınıfından türüyor.
Artık
YTL ytl = new YTL(8); Dolar dlr= new Dolar (8);
yerine
ParaBase ytl = new YTL(8); ParaBase dlr= new Dolar (8);
şeklinde tüm testlerimizi elden geçiriyoruz.(Resharper sağolsun)
Her değişiklikten sonra bütün testlerimizi tekrar çalıştırıyoruz.
Ortak metodları soyut sınıfımıza taşıdığımızda Dolar ve YTL sınıflarımızın içi boşaldı.Öyleyse bu arkadaşlara gerek yok.Bu sınıflarımızı uçurup Factory metod kullanarak sadece parabirimini temsil eden bir string alan ile istediğimiz kadar farklı türde para oluşturabiliriz.
ParaBase sınıfı içindeki yapıcı metodu kaldırıp yerine CreatePara statik factory metodunu yazıyoruz.
public static ParaBase CreatePara(int _miktar, string _birim)
{
return new ParaBase(_miktar, _birim);
}
Sınıfımızın son hali
public class ParaBase
{
public static ParaBase CreatePara(int _miktar, string _birim)
{
return new ParaBase(_miktar, _birim);
}
protected int miktar;
private readonly string birim;
protected ParaBase(int _miktar, string _birim)
{
miktar = _miktar;
birim = _birim;
}
public int Miktar
{
get { return miktar; }
}
public string Birim
{
get { return birim; }
}
public bool AyniMi(ParaBase yeniYtl)
{
return Miktar == yeniYtl.Miktar;
}
public void Ekle(int _ekMiktar)
{
miktar += _ekMiktar;
}
}
Dikkat edersiniz ParaBase sınıfımız artık soyut değil.Çünkü factory metodumuz içerisinde sınıfın yeni bir örneğini(instance) alıp döndürüyoruz.Soyut sınıflar new ile oluşturulamazlar.
return new ParaBase(_miktar, _birim);
Artık testlerimizde Para oluştururken şu şekilde yazıyoruz.
[Test]
public void YTL_YapiciMetodIleDuzgunOlusturulmus_Mu1()
{
ParaBase ytl = ParaBase.CreatePara(8, "YTL");
Assert.AreEqual(ytl.Miktar, 8);
}
Yeni bir test yazalım.
- Para çıkarma metodumuz olsun.
- Çıkarılacak tutar için yeterli para yoksa istisna fırlatsın.
[Test]
public void YTL_ParaTemelSinifiCikarMetodu()
{
ParaBase ytl = ParaBase.CreatePara(8, "YTL");
ytl.Cikar(3);
Assert.AreEqual(ytl.Miktar, 5);
}
Resharper, Cikar adında bir metod olmadığını farkedip bizi uyarıyor.Hemen ekliyoruz.
public void Cikar(int _cikacakMiktar)
{
miktar -= _cikacakMiktar;
}
Testimizi çalıştırdığımızda başarılı olduğumuzu görüyoruz.
Şimdi de para çıkarma işleminde elimizde yeterli para olmadığında istisna fırlatıyor mu onu test edelim.
[Test]
[ExpectedException(typeof(YetersizMiktarException))]
public void YTL_ParaTemelSinifiCikarMetodu()
{
ParaBase ytl = ParaBase.CreatePara(8, "YTL");
ytl.Cikar(13);
}
ExpectedException özniteliği(Attribute) NUnit ile gelir.Yazıldığı test içinden parametre olarak verilen türde bir istisna(exception) fırlatılmasını bekler.
Resharper, “YetersizMiktarException” adında bir sınıfın olmadığını farkeder ve bizi uyarır.Bu sınıfı aşağıdaki gibi oluşturuyoruz.
public class YetersizMiktarException : Exception
{
public YetersizMiktarException(string Message) : base(Message) { }
}
Şimdi de Cikar metodumuzu paranın yeterli olmadığı durumda istisna fırlatır hale getiriyoruz.
public void Cikar(int _cikacakMiktar)
{
if (_cikacakMiktar > Miktar) throw new YetersizMiktarException("Yeterli para yok");
miktar -= _cikacakMiktar;
}