Factory Method Pattern yaratım türleri içerisinde naçizane bir yere sahip müstesna bir class yaratım yoludur. Şöyle ki bazen bazı class ların üretimi ile ilgili bir başka class’ı sorumlu tutmak isteyebilirsiniz. Mesela bir class a ait event leri belli bir merkezde toplamak onların raise ettikleri eventleri bir noktadan görmek isteyebilirsiniz. Diyelim ki birkaç adet farklı işi yapan class’ınız mevcut, bu class ların yaptıkları işlerden sonra bir loglama merkezine işin bittiği sıradaki diğer işe geçildiği ile ilgili bilgi vermeleri gerekiyor. “Sub New” yaratımı ile bu işlemi yapıp sonra bu iş bitimi ile ilgili event’i bir shared metoda bağlamanız mümkün, ya da iş bittikçe shared bir metodu çağırmanız ama olabildiğince az modikasyonla en fazla genişlemeyi sağlayabilmek için (kısaca OCP) factory method pattern’ı bu gibi yerlerde kullanmamız gerekli olmaktadır.
Genel olarak “Factory Method” dediğimiz belli bir tür class ı yaratan ve döndüren bir fonksiyondan başkası değildir. Bir örnek kodla inceleyelim;
Public Class Fabrika
Shared Function Yarat(ByVal isim As String) As Hayvan
Dim h As New Hayvan
h.Init(isim)
Return h
End Function
End Class
<span id="more-76"></span>
Public Class Hayvan
Sub Init(ByVal isim As String)
_isim = isim
End Sub
Private _isim As String
Public ReadOnly Property İsim() As String
Get
Return _isim
End Get
End Property
End Class
Public Module MainApp
Sub New()
Dim kedi As Hayvan = Fabrika.Yarat("Tom")
Dim fare As Hayvan = Fabrika.Yarat("Jerry")
Console.WriteLine(kedi.İsim)
Console.WriteLine(fare.İsim)
Do
Console.ReadLine()
Exit Do
Loop
End Sub
End Module
Bu kodda görebileceğimiz üzere bir adet “hayvan” isimli class ımız ve o class a ait “İsim” özelliğimiz var. Shared olarak tanımlanmış “Yarat” metodumuz bize yeni bir hayvan yaratıp çıktı olarak gönderiyor. Bu örnekte mevcut değil ama mesela daha önceden aynı isimle yaratılmış bir class ı yeniden istediğimizde o obje yi yaratmadan var olanını döndürmeyi bu fabrika sayesinde sağlayabilirdik. Bu da yukarıda anlattığım “Factory Method Pattern” güzelliklerinden bir diğeri oluyor. “Object Reusability” diyebileceğimiz naçizane konu. Bu tip class ların kullanıldığı büyükçe bir kodlama düşünürseniz her hayvan class ını kullanacak olan farklı farklı kod rutinlerinde objeleri yeniden yeniden yarattırmak yerine yeniden kullanılabilirlilik adına “Factory Method Pattern” işimizi fazlasıyla kolaylaştırılıyor.
Neyse işin özü bu aslında ama burda göze çarpabilecek ve şu haliyle fabrikanın başaramadığı bir konu var. Mesela benim Hayvan class ından başka tipte, ya da hayvan class ından türemiş başka başka class larım var. Ve tüm bu türleri tek fabrikadan ürettirmem gerekli ise diyelim. Hepsi için ayrı ayrı birer fabrika yazabilirim mümkün ama 20 tane ayrı class varsa işin içinde nasıl bir kod olur o, nerde kalır OCP vs… O yüzden şimdi “generic factory” isimli bir fabrika yazacağım. Önce kod;
Public Class GenericFabrika
Shared Function Yarat(Of T)(ByVal isim As String) As T
If GetType(T).BaseType Is GetType(HayvanBase) Then
Dim obj As Object = Activator.CreateInstance(GetType(T))
Dim h As HayvanBase = DirectCast(obj, HayvanBase)
h.Init(isim)
Return obj
Else
Throw New Exception("Sadece HayvanBase sınıfından türeyenler bu fabrikada üretilebilir.")
End If
End Function
End Class
Public MustInherit Class HayvanBase
Sub Init(ByVal isim As String)
_isim = isim
End Sub
Private _isim As String
Public ReadOnly Property İsim() As String
Get
Return _isim
End Get
End Property
Overridable Function Tür() As String
Return "Genel bir hayvan"
End Function
MustOverride ReadOnly Property Renk() As String
End Class
Public Class Kedi
Inherits HayvanBase
Sub Miyavla()
Console.WriteLine("Miyavvv")
End Sub
Public Overrides Function Tür() As String
Return "Kedi"
End Function
Public Overrides ReadOnly Property Renk() As String
Get
Return "siyah"
End Get
End Property
End Class
Public Class Fare
Inherits HayvanBase
Public Overrides Function Tür() As String
Return "Fare"
End Function
Public Overrides ReadOnly Property Renk() As String
Get
Return "kahverengi"
End Get
End Property
End Class
Public Module GenericMainApp
Sub New()
Dim _kedi As Kedi = GenericFabrika.Yarat(Of Kedi)("Tom")
Dim _fare As Fare = GenericFabrika.Yarat(Of Fare)("Jerry")
Dim hayvanlar() As HayvanBase = {_kedi, _fare}
For Each h As HayvanBase In hayvanlar
Console.WriteLine(h.İsim & " isimli hayvan " & h.Renk & " renginde")
Next
_kedi.Miyavla()
Do
Console.ReadLine()
Exit Do
Loop
End Sub
End Module
Bu sefer fabrikadaki yarat fonksiyonumuzu generic olarak tanımladık. Bu yeni fonksiyonda ilk başta istenilen T türündeki çıktının aslında HayvanBase class ından türemiş olup olmadığına bakıyoruz. Programın durumuna göre gerekli olmayabilir ama böyle bir doğrulama ile koda başlamak mantıklı. Sonra işin sihir kısmı devreye giriyor “Activator” nesnesi: Burda görülebileceği üzere CreateInstance fonksiyonu da bir fabrika sayılabilir. Ama farklı bir şekilde generic tanımlanmış. Activator ile gerekli class ı yarattıktan sonra bu object class ı hayvanbase’e cast edip ortak olarak tanımlanmış “Init” metodunu çağırıyoruz.
Burada dikkat edilmesi gereken bir diğer nokta “HayvanBase” den türeyen nesnelerdeki özgürlüktür. Eskiden tek tür ile çalışırken hayvanın türüne göre bir eklenti yaptığımızda tüm hayvanlar için geçerli olması gerekirdi ama burada inheritance’ı tam anlamıyla kullanıyoruz. Ortak değerleri (mesela isim) tüm class larda ortak olacak şekilde base de tanımlarken hayvanlara ait özel bir metodu da ayrıca ve sadece o hayvana özgü biçimde tanımlayabiliyoruz (mesela miyavla). Ek olarak türeyen class lara bazı gerekli metodları tanımlaması için zorlayabiliyoruz (mesela Renk). Bunlar generic factory ile alakadar olmayan şeyler tabi hepsi inheritance ın güzellikleri ancak bu şekilde tanımlayınca fabrikamızı hem OCP ye daha bir uygun kod ortaya çıkıyor hem de inheritance ı fazlasıyla kullanıyoruz…
Yorumlar kapalı.