Abstract Factory Tasarım Deseni

header_abstract_factory

Yaratımsal desen kategorisinde yer alan diğer bir desen ise abstract factory desenidir.Bu desenin birbiriyle ilişkili veya bağlı olan sınıfların (nesne ailelerinin) üretiminin tek bir arayüz veya soyut sınıf ile yapılmasını sağlar.Böylece tek bir sınıf ile istenilen nesne aileleri üretilmiş olur.

Bu desen için verilen en popüler örnek veritabanı provider yapısıdır.Veri odalı bir yazılım sisteminin veritabanı olarak MS-SQL kullandığını varsayın ve veri işlemleri için doğrudan framework tarafından sağlanan SQL sınıflarını kullandım.Bu kod yazış biçimi bizi aşırı bağımlı bir yapıya götürüyor.Sistemimizin veri kaynağının değişmeyeceğini öngörüyor olsak bile framework sınıfları wrap edecek sınıflar yazmamız gerekir.Yazılım kaynağının değişeceğini ya da sistem içerisinde bazı modüllerin Oracle bağlantısına göre bazı modüllerinin ms-sql veritabanına göre davranması gerekebilir.Bu bahsettiğim senaryo aslında bir veri erişim modelinin (Connection,Command,Transaction) diğer bir deyişle ürün ailesinin farklı tiplerde olabileceğini farklı versiyonlarının olacağını görüyoruz.Bu gibi senaryolar da soyut fabrika desenini kullanabiliriz.Bu senaryoya ait örnek kod parçasına buradan ulaşabilirsiniz

Benzer yapı .NET Base Library içerisinde yer alıyor.

untitled

Genel olarak soyut fabrika deseni ;

  1. İlişkisi veya bağlılığı bulunan nesnelerin üretimi efektif ve kolay bir şeklide gerçekleşir.
  2. İstemci doğrudan asıl ürünle konuşmaz.Asıl ürüne erişmek istediğinde onun için tanımlı olan arayüz ile konuşur.Böylelikle ürün ailesindeki değişiklikler istemci kodunda herhangi bir değişikliğe ihtiyaç duymaz.Aynı zamanda daha test edilebilir bir yapı ortaya çıkmış olur.
  3. Asıl ürünlerden soyutlanmış sınıflar veya arayüzler üzerinden kullanıldığı için kolayca başka nesne grupları gerekli implementasyonlar yapıldığı takdirde desen içerisine ve üretime dahil edilmiş olur.
  4. Birbiri ile ilişkileri olan nesneleri üretimini soyutlamak için sorumlu işlem methodlarında basit if-else , switch ifadelerini kullanarak da gerçekleştirebiliriz.Fakat bu tarz bir kodlama değişim ve ekleme işlemleri için sıkı kod yazılmasını beraberinde getirebileceği gibi işlem methodların sorumluluk alanının dışına çıkılmış olunur.Üretimde if-switch gibi alt seviye kodlar kullanılmadığı için değişimlere kolayca ayak uydurur.
  5. Factory method deseni yerine soyut fabrika desenini kullanabiliriz.
  6. Genel olarak fabrika method sınıflarını genelleştirmek için kullanılır.

 Tasarım

Aşağıda desenin UML diagramını görüyoruz.

capture

 

Desene ait bazı kavramlar ;

Concrete Product; Birbiriyle ilişkisi bulunan nesneler ve asıl üretilmesi istenilen nesnelerdir. (ProductA1 , ProductA2 , ProductB1 , ProductB2)

Abstract Product; birbiriyle ilişkisi bulunan sınıfları tek bir tip altında tanımlayabilmek için kullanılır.Concrete product  sınıfları tarafından uygulanır veya implement edilir.İnterface ve abstract class olarak yazılabilirler. (IProductA , IProductB)

Concrete Factory ; İçerisinde nesne ailesine ilişkin concrete product nesnelerinin üretiminde sorumlu methodları içerir.Asıl fabrika sınıflarıdır.Bu sınıf abstract factory sınıfını gerçekleştirirler.(Factory1 , Factory2)

Abstract Factory ; Factory sınıfları için soyut bir tip sağlar ve içerisinde yine abstract product sınıfları için methodlar bulunur. (IFactory)

Bir kaç tasarım alternatifleri

  • Burada nesnelerin oluşturulması concrete factory sınıfları içerisinde gerçekleşir.Nesne oluşturma sürecini burada istediğiniz gibi  kurgulayabilirsiniz. Örneğin nesne oluşturmak için Dependency Injection gibi yapıları kullanabilirsiz
  • Factory sınıflarının fazla olduğu durumlar da generic bir factory sınıfı kullanabilirsiniz.
  • Delegate tabanlı factory sınıfları tasarlayabilirsiniz.
  • Yazacağınız fabrika sınıflarının istemci kod tarafından doğrudan kullanılması yerine bunun için bir wrapper sınıf yazarak tek bir factory tipi ile o ürün ailesi ile ilgili tüm alt sınıfların üretilmesini ve ilgili temel işlemlerin yapılmasını sağlayabilirsiniz.

Örnek Senaryo ve kodlama

Raporlama ile ilgili örnek bir senaryomuz var.Bir online bankacılık uygulmasın da müşterilerin günlük veya aylık gibi çeşitli periyotlarda hesap hareketlerini alabildiği bir fonksiyonellik düşünün.Teknik olarak elimde bir veri seti var ve bu veri setini seçeneğe göre excel veya pdf olarak bir çıktı üretmem gerekiyor.Bu ihtiyaç için iş çatısının (business framework) ilgili yerine bu fonksiyonelliği sağlayacak kodları yazıyoruz.Aşağıda başlangıçta kullanacağım kodlarım yer alıyor

Kodlara baktığınızda rapor tipinden bağımsız olarak 3 işlemsel fonksiyonum (ReportConnector,ReportFormatter,ReportWriter) var.Bunlar bir ürün ailesini temel fonksiyonları ve bunların kalıtımı sonucunda PDF ve excel için iki farklı ürün ailesi elde ediyoruz.

Yukarıda fabrika sınıflarının kodlamalarını göreceksiniz.Ek olarak bu sınıfların nasıl kullanılabileceğinide örneklemiş olduk.İstemci kodun doğrudan fabrika asıl fabrika sınıflarına erişmemesi için ReportGenerator sınıfını tanımladım.Bu sınıf aracılığıyla raporlamaya dair bir çok iş gereksinimi gerçekleştirebilirim.Tabi biraz method eklemeniz gerekebilir.Ayrıca bu sınıfın genişleyebileceğini düşündüğüm için statik bir sınıf olarak tanım yapmadım ve  çalışma zamanında tek bir instance nın olması için singleton olarak tasarladım.

Şimdi de örnek uygulamamızın sınıf diagramını görelim.

capture_2

İlişkili desenler

Bu desen Factory method deseni ile benzerlikler gösterir.Tek farkla bir fabrika sınıfı yerine birden fazla fabrika sınıfını barındıracak soyut bir sınıf yaratılır.Bu desen fabrikaların fabrikası olarak da isimlendirilir.

Şimdilik bu kadar.Yazıda yanlış olduğunu düşündüğünüz yerleri lütfen yorumlayın 😀

Factory Tasarım Deseni

header_factory

Yaratımsal kategoride yer alan diğer tasarım deseni factory desenidir.Aynı arayüze veya soyut sınıfı uygulayan sınıfların nesnelerinin oluşturulmasından sorumludur.Bu sınıflardan nesne oluşturma işlemi  sınıfın uyguladığı arayüz veya soyut sınıf aracılığıyla fabrika sınıfları tarafından oluşturulur.

diagram_factory

Yukarıda bir sınıftan nesne oluşturulmasına yönelik bir diagram görüyorsunuz.Yeni yazdığımız bir sınıftan nesne oluşturmak istediğimizde doğrudan new anahtar kelimesini kullanarak nesne yaratım işlemini gerçekleştirebiliriz.Bu desen ile istemci kodun bu sınıftan nesne oluşturması için araya factory yapısını yerleştiriyoruz.Desenin mantıksal modeli bu şekildedir.Teknik açıdan bakıldığında bir kaç kalıtılmış sınıfından nesne üretilmesi için kullanılır.

Factory deseni ile bir sınıfın nesne oluşturma ve fonksiyonellikleri birbirinden ayrılmış olur.İstemci kod doğrudan asıl sınıfın fonksiyonelliğine erişemez.Asıl sınıfın fonksiyonellikerine erişmek için factory methodu veya sınıfı aracılığıyla asıl sınıfından bir instance oluşturur ve bu şeklide fonksiyonelliklere erişebilmiş olur.İstemci ve işi yapacak olan sınıf fonksiyonellikleri birbirinden ayrıldığı için gevşek bağımlılık sağlanmış olur.

Bu desenin Enterprise Library içerisinde Unity blogu içerisinde kullanıldığını buradan görebiliriz.Örneğin bir bankacılık istemi içerisinde bir çok çeşit ödeme dosyası sistemde izlenilen bir dizine düşüyor.Bu dizine düşen dosyaları işlemeniz ve bu bilgileri sistem içerisine entegre etmeniz gerekiyor.Burada dosya tipine bağlı olarak (xml,txt,xlsx) farklı işler yapacaksınız fakat dosya tipinden bağımsız olarak dosyayı açmanız(open), belirli validasyonlardan geçirmeniz (valid) ve ayrıştırmanız (parse) gerekiyor.Bu gibi ortak özellikler için arayüz tanımlanır.Her bir dosya tipi için tüm fonksiyonları içeren ayrı ayrı sınıflar yazılıp bu işlemleri o şeklide gerçekleştiririz.Bu gibi ortak karakteristiği olan sınıfların nesne örneğinin oluşturulması için bu deseni kullanımı güzel bir strateji olabilir.

Tasarım

factory-implementation

Yukarıda en temel şekli ile factory deseninin UML şemasını görüyorsunuz.Factory desenin temel olarak 2 farklı şeklide uygulama yöntemi vardır.Birinci yöntemde nesnelerin oluşturulması için Creator veya Factory soneki almış bir sınıf bir sınıf içerine tek bir method araılığıyla oluşturulur.Diğer yöntemde ise her nesne için ayrı bir factory sınıf yazılır.İki yönteminde yaptığı iş aynı kurgusu farklıdır.Fakat ikinci yöntemi tercih ettiğimizde yeni eklemeler daha rahat olacaktır.

Factory Method

Aşağıda ilk yöntem için yazılan kod örneğini görüyoruz.Burada dökümanları okumak için altyapı oluşturulmaya çalışıyor.Burada generic kullanım şeklini de görüyorsunuz.

Factory Sınıfı

Bu yöntemde ise concrete sınıflarımız için factory sınıfları yazıyoruz.Yani PDFReader ve MsWordReader sınıfları için PDFReaderFactory ve MsWordReaderFactory sınıflarını tanımladık.Kullanım kısmında göreceğiniz gibi nesne örnekleri için bu factory sınıflarını kullanıyoruz.

Örnek Kodlama

Örnek kodlamamızda Muhasebe gerçekleştirim işlemi için sınıf yapılarını oluşturmaya çalışlıyoruz.Burada muhasebesi yapılacak işlemin türünden (yurtiçi,yurtdışı,avrupa ödemesi) bağımsız olarak Teknik bazı ortak fonksiyonellikleri var bunun için interface ve soyut sınıf tanımladım.Kurguladığım bu örnek için her bir asıl sınıf için factory sınıfları tanımladım ve muhasebe akış sınıfı için bu factory sınıflarını kullandım.

Örnek kodlarımızın sınıf diagramını görelim.

 

capture_diagram

Sonuç

Birbirine yapısal olarak farklı ama bazı ortak özelliklere sahip -interface veya abstract kalıtımı- sınıfların nesnelerinin oluşturulmasını sağlar.Aynı zamanda nesne oluşturma sürecini merkezi hale getirerek belirli kriterlere göre hangi nesnenin oluşturulacağı gibi kararlarının alınmasına da yardımcı olur.

İlişkili olduğu desenler

  • Null Object Pattern ; hiç bir duruma girmeyen durumlarda var sayılan olarak nesne gönderilmesi durumunda NULL tanımlı bir nesne örneğinin gönderilmesi düşünülebilir.

Şimdilik bu kadar.Yazıda yanlış olarak ifade edilen noktalar görürseniz lütfen yorumlayın :D

Singleton Tasarım Deseni

header

Yaratımsal desenler içerisinde yer alan singleton bir sınıfın uygulama yaşam süresi boyunca tek bir nesne örneğinin oluşturulmasını sağlamak için kullanılır.Ayrıca singleton olarak tasarlanan sınıfın global bir erişim seviyesine sahip olmasını da garanti eder.Bir sınıfın örneğinin oluşturulması istediğimizde newanahtar kelimesini kullanırız.Bu anahtar kelimeyi kullandığımız sınıflara bakıldığında yapıcı methodun erişim belirleyicisinin public olduğunu görürsünüz.Yeni yazılan sınıfların yapıcı methodu varsayılan olarak gizli bir puclic yapıcı methoduna sahiptir böylelikle new anhatar kelimesiyle nesneyi oluşturabiliyoruz.Singleton olarak tasarladığımız sınıflar da bu yapıcı method dışarıdan erişime kapatılarak sınıftan nesnelerin oluşturulması engellenmiş olur.Bir sınıfı singleton olarak tasarlamak istediğimiz de aşağıdaki bir kaç adım bize yardımcı olacaktır.

  • ilk olarak sınıftan nesne oluşturulmasını sağlayan yapıcı methodun erişim belirleyicisi private veya protected yapılarak dışardan erişime kısıtlanır.Bunu yaparak sınıfın new  ile oluşturulması engellemiş oluyoruz
  • Sınıfı sealed olarak işaretleyebiliriz
  • Nesne yaratmak için sınf içerisinde kendi tipinde private erişime sahip static bir değişken tanımlanır.
  • Son olarak singeleton tipimizi temsil etmek için static ve public olarak bir method veya propertytanımlıyoruz.Bunun içerisinde nesnenin yaratılması sağlanıcak.Bu method veya property yi kullanarak istemci nesneye erişim sağlar.

singleton-design-pattern

İstemci kod parçası singleton olan sınıfın örneğinin oluşturmak istediğinde eğer daha önce hiç nesne oluşmadıysa ilk olarak nesne oluşur fakat daha sonraki nesne çağrımlarında daha önce oluturulan nesne gönderilir.Yukarıdaki resimde geleneksel ve singleton implementasyonunu görebilirsiniz.

Uygulanabilirlik

Singleton deseni aşağıdaki durumlarda kullanılabilir.

  • Bir sınıftan sadece bir nesne örneğini,n olması öngörüldüğünde
  • Singleton uygulanacak sınıfın global bir erişim seviyesine sahip olması durumunda ve uygulamanın diğer tüm bileşenleri bu sınıfa erişilebilmeli
  • Sınıftan nesne oluşturması masraflı olduğu durumlar da 
  • Singleton olması istenen sınıfın yapıcı methodu parametresiz olması gerekir

Singleton deseni kullanılma sıklığı diğer desenlere göre daha fazladır ve çok daha kolay uygulanır.Bir framework tasarımında genelde caching , logging , kaynak tüketim sınıfları (database connections,file processor) gibi sınıflar singleton olarak tasarlanır.

Tasarım

Desenin UML şemasını görelim.

singleton_diagram

Singleton desenenin single-threaded ve multi-threaded olarak iki farklı gerçekleştirim yönetemi vardır.Kodunuzun bulunduğu ortamın multi-thread olup olmamasına bağlı olarak bu yöntemler kullanılır.Aşağıda farklı singleton uygulama versiyonlarını görelim.

Thread safe olmayan kod örneği

Bu kod parçacığı Thread safe bir kod değildir.Eğer iki farklı thread yakın zaman dilimlerinde bu sınıftan Instance methodunu çağırırsa iki ayrı nesne oluşur.Singleton deseninin gereklilikleri sağlanmamış olur.Bu kod tamamiyle teorik olarak singleton desenini uygulamıştır.Kullanılması önerilmez.

Thread Safe kod örneği

Singleton deseninin bu versiyonu thread-safe versiyonudur. Thread paylaşılan bir nesne üzerinden (lock) kilitlenir ve nesne örneğinin yaratılıp yaratılmadığını kontrol eder.

Lazy initialization

Lazy initialization bir nesnenin yaratılmasını geçiktirmek için bir taktiktir.Nesne ihtiyaç duyulacağı son ana kadar nesne yaratılmaz.NET 4 ile Base Class Library içerisine dahil olan generic Lazy tipi ile Lazy Initialization  işlemini gerçekleştiriyor.Bu tipi kullanarak singleton desenini kolaylıkla uygulayabiliriz.

Generic Singleton

Singleton desenini uygulamak istediğimizde , varolan sınıfın düzenlememiz gerekir.Tipten bağımsız bir şeklide bir sınıf singleton yapmak istersek  generic singleton ile kolaylıkla bunu gerçekleştirebiliriz.

Gerçek hayat örneği

Uygulamalarımızda kullanıcının yaptığı işleme göre hata mesajı , uyarı mesajı veya işlemin sorunsuz tamamlandığına dair bir mesaj veririz.Verdiğimiz bu mesajları kodumuza doğrudan yazmak yerine bunun için bir key tanımlayıp bu key e karşılık gelen string ifadeyi uygulamanın veri kaynağında key-value şeklinde tutmak istediğimiz düşünün ve bunun için de gerekli olan StringManager sınıfını yazdık.Fonksiyonel olarak düşündüğünüzde StringManager sınıfına uygulamanın her yerinden (app , uı) istek de bulunulabilir ve istenildiği kadar nesne oluşturulabilir.Bu aşırı kaynak üretimine ve uygulama yavaşlamasına sebep olacaktır.Bu sınıfı aşağıdaki şekilde singleton olarak tasarladık.

İlişkili olduğu desenler

  • Abstract Factory daki gerekli görülen ConcreteProduct sınıfları singleton tasarlanır.
  • Factory Method
  • Builder 
  • Durum sınıfları sıklıkla singleton olarak tasarlanır.
  • Alt sistemleri oluşturan Facade tipleri singleton tasarlanır.

Sonlandırırken

Singleton deseni genel olarak test edilmesi zor olduğundan mümkün olduğunda kullanmamak gerekir ve bu sebeple çoğunlukla anti-pattern olarak algılanır.Bunun yerine IoC Container gibi yapıları kullanmak daha efektif bir çözüm olarak görülür.

Peki neden bir sınıfı static yerine singleton tasarlamalıyım ?

Genel olarak bakıldığında singleton deseninin sağladığı fonksiyonelliği static sınıfların da karşıladığını düşünebiliriz.Fakat static sınıflar singleton yapılardan tamamiyle farklıdır.Şimdi bu yapılar hakkındaki bir kaç önemli noktaya bakalım.

  • Static sınıflar sistemdeki global verilere erişim için kullanılabilir. hızlı erişim ve performans sağlar
  • Singleton sınıflar geleneksel sınıf yapısını korur , static sınıfların kullanılması nesne yönelimli prensiplerden uzaklaştırır.
  • Singleton tasarladığımız sınıflar üzerinden kalıtım yapabiliriz diğer taraftan static sınıflarda kalıtım yapılamaz
  • Singleton ihtiyaç olduğu durumlarda lazy olarak tasarlanabilir.

Şimdilik bu kadar. Aşağıda kaynak kodları ve dökümanları bulabilirsiniz.Yazıda yanlış olarak ifade edilen noktaları görürseniz lütfen yorumlayın 😀

Interpreter design pattern

You can see a sample implementation of the interpreter design pattern.it’s possible smilliar to each other definitions for interpreter in internet literature.

  •  interpreter pattern is a design pattern that specifies how to evaluate sentences in a language
  • Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
  • Map a domain to a language, the language to a grammar, and the grammar to a hierarchical object-oriented design

Sample scenarios for this pattern

  • read barcode
  • roman numbers converting numbers   –   (X == 10)
  • Total ASCII values ​​of the characters  – (A == 65)
  • reading result operations with mathematical and logical operators (10*5-3==47)
  • analysis of the encrypted text

Now let’s take a look our sample codes and diagram

ClassDiagram1

Main classes

example of use:

see you blog post

also get clone using VisualStudio 2012 with git source control in the bitbucket repository.You can see repository address and git address in the below

Repository : https://bitbucket.org/yemrekeskin/interpreter.designpattern

Git : https://yemrekeskin@bitbucket.org/yemrekeskin/interpreter.designpattern.git to get clone repository