Makale Özeti

Tasarım desenleri kategorisinde yer alan desenler nesne veya nesne gruplarının üretimi(instance) ile ilgili efektif çözümler sunarlar.Bu yazımda bunlardan biri olan Soyut fabrika tasarım desenini (Abstract Factory Design Pattern) incelemeye çalışacağım.

Makale

Herkese merhaba

Tasarım desenleri kategorisinde yer alan desenler nesne veya nesne gruplarının üretimi(instance) ile ilgili efektif çözümler sunarlar.Bu yazımda bunlardan biri olan Soyut fabrika tasarım desenini (Abstract Factory Design Pattern) incelemeye çalışacağım.

Soyut fabrika deseni birbiriyle ilişkili veya bağlı olan sınıfların (nesne ailelerinin) üretiminin tek bir arayüz ile yapılmasını sağlar.Böylece tek bir sınıf ile istenilen nesne aileleri üretilmiş olur.

Desenin sağladıkları;

* İlişkisi veya bağlılığı bulunan nesnelerin üretimi efektif ve kolay bir şeklide gerçekleşir.

* İstemci doğrudan asıl ürünle konuşmaz.Böylece istemcinin yazdığı kod değişimden etkilenmez.

* Asıl ürünlerden soyutlanmış sınıflar kullanıldığı için kolayca başka nesne grupları gerekli implementasayonlar yapıldığı takdirde desen içerisine ve üretime dahil edilmiş olur.

* 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.

Daha bir çok aklımıza gelmeyen avantajını saymak mümkündür.Kullanım sıklığı çok olan bir desendir.Desen kendi başına kullanılabildiği gibi diğer desenlerle de kullanılır.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.

Desene ait kavramlar;

Concrete Product; Birbiriyle ilişkisi bulunan nesneler ve asıl üretilmesi istenilen nesnelerdir.

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.

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.

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.

Şimdi anlatılan bu kadar kavramsal ifadelerden sonra kod yazmaya başlayalım.Bu desende çok sıklıkla kullanılan bir senaryoyu gerçekleştireceğiz.Veritabanlı bağlantılarında kullanılan ve bağlanılan kaynağa(Mysql,Oracle,MS-SQL,Db2) göre farklılık gösteren Connection-Command-Parameter-Transaction gibi ilişkili nesnelerin üretimini bu deseni uygulayarak veri kaynağından bağımsız bir şeklide gerçekleştireceğiz.

Hadi kod yazalım.

/// <summary>
/// Abstract Product
/// </summary>
abstract class Command { }
abstract class Connection { }
abstract class Transaction { }

İlk olarak abstract Product sınıflarını yazdık sonrasında bu sınıfları uygulayacak asıl ürün sınıflarını yazıyoruz. 

/// <summary>
/// Concrete Product for Oracle
/// </summary>
class OracleCommand
    : Command
{
}

class OracleConnection
    : Connection
{
}

class OracleTransaction
    : Transaction
{
}

/// <summary>
/// Concrete Product for MySql
/// </summary>
class MySqlCommand
    : Command
{
}

class MySqlConnection
    : Connection
{
}

class MySqlTransaction
    : Transaction
{
}
 Şimdi fabrika sınıflarımızı yazabiliriz.İlk olarak asıl fabrika sınıflarımızın uygulayacağız soyut fabrika sınıfımızı yazalım. 
/// <summary>
/// Abstarct Factory
/// </summary>
abstract class DbFactory
{
    public abstract Connection Connection();
    public abstract Command Command();
    public abstract Transaction Transaction();
}
  Sıra geldi soyut fabrika sınıfını uygulayacak asıl fabrika sınıflarını yazmaya, 
/// <summary>
/// Concrete Factory for Oracle
/// </summary>
class OracleDbFactory
    : DbFactory
{
    public override Connection Connection()
    {
        return new OracleConnection();
    }

    public override Command Command()
    {
        return new OracleCommand();
    }

    public override Transaction Transaction()
    {
        return new OracleTransaction();
    }
}

/// <summary>
/// Concrete Factory for MySql
/// </summary>
class MySqlDbFactory
    : DbFactory
{
    public override Connection Connection()
    {
        return new MySqlConnection();
    }

    public override Command Command()
    {
        return new MySqlCommand();
    }

    public override Transaction Transaction()
    {
        return new MySqlTransaction();
    }
}
 

Yazılan kodlardan sonra aslında desen ile ilgili geliştirmelerimiz yeterli görünüyor.Şu aşamada istemci ilk olarak fabrika sınıfında örnek aldıktan sonra istediğiilgili sınıflara (Connection-command-transaction) ulaşabilir.Diğer sınıflara istemcinin erişememesi için erişim düzenleyicileri tanımlarken dikkat etmek gerekir.Şimdi bunu bir istemci olarak kullanalım. 

 
DbFactory MySqlFactory = new MySqlDbFactory();
MySqlFactory.Connection();
MySqlFactory.Command();
MySqlFactory.Transaction();


DbFactory oracleFactory = new OracleDbFactory();
oracleFactory.Connection();
oracleFactory.Command();
oracleFactory.Transaction();
 

Bu şeklide kullandık.Fakat buradaki işlemlerde asıl amaç veri ile iletişim kurmak (en azından senaryo gereği) ve bu bu iletişimi kurarken tek bir nesneyi değil ilişkili bir çok nesneyi kullanmamız gerekiyor(Soyut sınıflar).Bu gibi durumlarda ilişkili nesneleri kullanan bir veri erişim blogu (DataAccessBlock)yazılır.Bizde doğrudan istemcinin  bir çok nesneyi kullanmasında zorluğu görerek bunu tek bir veri erişim sınıf kullnarak yapacağız.Bu sınıfta doğrudan soyut fabrika sınıfını kullanarak nesneleri üretecek ve işlemeleri bu sınıflar aracılığıyla gerçekleştireceğiz. 

Şimdi bu durumla ilgili kodları yazalım.

 
interface IDataBlock
{
    void Open();
    void Close();
    void Execute(string query);
    DataTable GetList(string query);
    int GetRecordCout(string query);
}

protected class DataAccessBlock
:IDataBlock
{
private DbFactory Factory;
private Connection Connection;
private Command Command;
private Transaction Transaction;

public DataAccessBlock(DbFactory factory)
{
    this.Factory = factory;
    this.Connection = Factory.Connection();
    this.Command = Factory.Command();
    this.Transaction = Factory.Transaction();
}
        
public void Open()
{
    throw new NotImplementedException();
}

public void Close()
{
    throw new NotImplementedException();
}

//...
 
Bu şekilde istemcinin kolayca işlem yapabilmesini ve daha bir çok şeyi olabilecek durumları düşünerek kodladık.Şuana kadar yazdığımız kodlara bakarsanız çok fazla ve complex bir yapısı var, ilk bakışta anlaşılabilecek bir tarzda kod değil(en azında ben böyle düşünüyorum).Bu tür kodların tek bir hedefi olduğu için her sınıf ayrı bir kod dosyasında yazmaktansa tek bir dosyada bütün sınıfları barındırmak çok daha iyi olacaktır.Şimdi yazılan kodları class-diagram üzerinde görelim.
 

Peki ya bu tür problemler ve isterler daha önce düşünülmedi mi ?  

Kesinikle düşünüldü , .NET Framework içerisinde zaten böyle bir mekanizma mevcut yani bizim kullandığımız SqlConnection ve OledbConnection sınıflarının orta arayüzleri implemente ederler.Biz Framwork ün sağladığı bu arayüzleri kullanarak  yukarda yazdığımız kodları daha az efor ile yazabilirdik.

 
 

Bu şekilde Framework istemcinin isteklerine göre kullanılan bu arayüzleri implemente ederek custom bağlantı tipleri için gerekli nesneleri elde etmiş olur.Oracle,Mysql ve daha bir çok kaynak için geliştirilen dll ler bu arayüzleri kullanırlar.Framework programcıları olabilecek bütün durumları göz önüne alarak çok daha esnek kod yazarlar ve istemciye kolaylıkla cevap verirler. 

Sonuç olarak; 

Soyut fabrika tasarım desenine en basit şeklide uygulamaya ve anlatmaya çalıştım.İstemciden olabildiğince soyut ve kolay kullanımı olan kodlar geliştirdik.Üzerinde kod yazdığımız Framework ü iyi tanımakda yazdığımız kodun kalitesini de arttırır ve gereksiz efor kaybetmekden bizi kurtarır. 

Şimdilik bu kadar , iyi kodlamalar dilerim...