Abstract Factory Pattern Kullanimi .NET Design Pattern



Abstract Factory Pattern tek bir arayüz ile bir ürün ailesini(product family) bir çatı altında toplamak diyebiliriz. Daha önce anlatmış olduğumuz factory pattern reflection kullanimi konusuna Abstarct Factory içerisindede rastlıyacağız.
Bu kullanıma bir örnek vermek gerekirse eğer Ado.NET'den SqlConnection, SqlCommand sınıflarını düşünün. Bir SqlCommand'ın bir connection ihtiyacı vardır ve buda SqlConnection olmalıdır. Çünkü bunlar bir ürün ailesi yani product family'dir. Bizde bu yazımızda kendi ürün ailemizi oluşturacağız. Öncelikle "connection" sınıfımız ile başlıyalım.

 public abstract class SCConnection
    {
        public abstract void Open();
        public abstract void Close();
    }

"SCConnection" bizim arayüz connection nesnemiz. Burdan türeyen nesneler "Open, Close" methodlarını kullanmak zorunda olucaklar. Buda bizim connection açma kapama işlerini yapacağımız noktalarımız olacak. Connection olarak "Sql ve Oracle" neslerimiz olsun diyelim.

 public class SqlConnection : SCConnection
    {

        public override void Open()
        {
            Console.WriteLine("Sql connection açıldı");
        }

        public override void Close()
        {
            Console.WriteLine("Sql connection kapatıldı");
        }
    }

 public class OracleConnection : SCConnection
    {
        public override void Open()
        {
            Console.WriteLine("Oracle connection açıldı");
        }

        public override void Close()
        {
            Console.WriteLine("Oracle connection açıldı");
        }
    }

İçinde "connection" barındıracak olan bir de command arayüz sınıfına ihtiyacımı var. Bu sınıfada "SCCommand" adını veriyoruz, bu class ise bu şekilde olacak ;

 public abstract class SCCommand
    {
        public SCConnection Connection { get; set; }
        public abstract object ExecuteQuery(string queryValue);
    }

"Connection" her bir command için olması gereken bir sınıf. Aynı zamanda her SCCommand'dan türüyen nesneler "ExecuteQuery" metodunu uygulamak zorunda. Bu classlara örnek vermek gerekirse şu şekilde olabilir ;

  public class SqlCommand : SCCommand
    {
        public override object ExecuteQuery(string queryValue)
        {
            return "Sql query çalıştırıldı. Query : " + queryValue;
        }
    }
   public class OracleCommand : SCCommand
    {
        public override object ExecuteQuery(string queryValue)
        {
            return "Oracle query çalıştırıldı. Query : " + queryValue;
        }
    }

Şimdi connection, command sınıfılarımız ve bunlardan türeyen Sql, Oracle ürün aile sınıfılarımız tamamlandı. Şimdi bunlara ürün aile özelliği katıcak bir arayüz sınıfına ihtiyacımız var. Buna "DbProvider" diyorum, bunun class görünümü ise şu şekilde ;

 public abstract class SCDbProvider
    {
        public abstract SCConnection CreateConnection();
        public abstract Command.SCCommand CreateCommand();
    }

Bu bizim arayüz provider nesnemiz. Bundan türeyen her nesneden bize "SCConnection, SCCommand" vermesini istiycez. Bundan türemesi gereken nesneler ise tahmin edildiği gibi "SqlDbProvider" bize sql ile alakalı olan ürün ailesini oluşturacak.
"OracleDbProvider" bize Oracle ile alakalı ürün ailesini oluşturacak. Sadece "SqlDbProvider" nesnesine göz atalım. OracleProvider'da zaten aynı şekilde olucak. Onuda siz türetebilirsiniz. Yazımın sonunda projeyi paylaşıcam zaten.

 public class SqlDbProvider : SCDbProvider
    {
        public override Connetion.SCConnection CreateConnection()
        {
            return new SqlConnection();
        }

        public override Command.SCCommand CreateCommand()
        {
            return new SqlCommand();
        }
    }

Görüldüğü gibi bizden "SCConnection ve SCCommand" isteyen provider methodlarını ezerek "SqlConnection ve SqlCommand" instance aldık. Ve bu bizim için Sql Product Family oldu diyebiliriz. Bunu tabiki çeşitlendirmek bizim elimizde.
Şuana kadar birbirine "Connection > Command" bağlantısı dışında bağlantısı olmayan istenildiği Oracle, istenildiğinde Sql ailesini kullanabileceğimiz bir yapı oluşturduk. Peki, bu providerların instance alma görevini kime verelim ? Burdada devreye Factory Pattern giriyor. Bu factory işlemini yapacağımız sınıf "SCDbProviderFactory" adında olsun.


        static Dictionary _providers;
        static object _locker = new object();
        public static SCDbProvider GetDbProvider()
        {
            if (_providers == null)
                _providers = new Dictionary();
            string providerTypeName = System.Configuration.ConfigurationManager.AppSettings["dbProviderKey"];
            if (_providers.ContainsKey(providerTypeName))
                return _providers[providerTypeName];
            lock (_locker)
            {
                Type providerType = Type.GetType(providerTypeName);
                SCDbProvider dbProvider = (SCDbProvider)Activator.CreateInstance(providerType);
                _providers.Add(providerTypeName, dbProvider);
                return dbProvider;
            }
        }

Bu sınıf bizim için app.config'e "dbProviderKey" adında yazdığımız değişkeni alıp ilgili sınıfı instance alıcak sınıfdır. "GetDBProbider" methodunun iş kısmını geçiyorum, daha önceki yazılarda anlatmıştık. Son olarak bizim developer'ın kullanacağı bir manager nesnesine ihtiyacımız var. Yani developer bu çalışmalara dahil olmadan "DbManager.Select("query")" methodu cağırarak işini görmeli. Arka tarafta sql mi ? oracle mi ? bilmemeli. Bilmesinede gerek kalmamalı.

 public class DbManager
    {
        public static object Select(string query)
        {
            SCDbProvider dbProvider = SCDbProviderFactory.GetDbProvider();
            SCCommand command = dbProvider.CreateCommand();
            command.Connection = dbProvider.CreateConnection();
            return command.ExecuteQuery(query);
        }
    }

Artık bunu developer basit bir şekilde kullanabilir.

 DbManager.Select("Select * from Developers Where Email='sametcinar@msn.com'");

Böylece developer için araştırma süresi, öğrenme süresi v.b durumlar ortadan kalkmış olucaktır.
Bu anlatımı yaparken kullandığım küçük projeyi indirebilirsiniz. Abstarct Factory Pattern

Yorum Yaz