Caner Tosuner

Leave your code better than you found it

Builder Design Pattern

Design pattern'leri spagetti kodlara veya tekrar eden kod bloklarına çözümler olarak ortaya çıkmışlardı. Builder Design Pattern creational patterns kategorisi altında bulunan patternlerden birisidir ve kısaca basit objeler kullanarak complex objeler inşa etmede kullanılır diyebiliriz. 

 

Builder'ı DTO yani data transfer object class'larını örnek olarak düşünürsek, bu objeler birden fazla objenin birleşmesinden oluşurlar ve genelde complex objelerdir. Builder pattern'nini de base'de bir obje var ve bu objeye ait alt property'leri oluştururken her bir özellik için ayrı build metotları yazmamız gerekir. Builder design pattern'i bu gibi durumlarda kullanabilecegimiz bir pattern olarak dusunebiliriz. Başka bir deyişle; runtime da yaratılması gereken complex objelerinizin olduğu bir projeniz varsa bu pattern'i kullanmak güzel bir seçim olabilir veya adım adım obje yaratma işlemlerini yönetmek istediğiniz bir durum var ise yine bu pattern'i kullanabiliriz.

Builder pattern'i 4 ana yapıdan oluşur;

  • Product  : Build edilen obje,
  • Builder   : Product'ı build eden abstract yapı,
  • Concrete Builder : Builder nesnesinin abstract yapıyı kullanarak aynı yapıdaki farklı ürünlerin build edilmesini sağlayan yapı,
  • Director  : Kendisine verilen Builder'ı property'lerini kullanarak ürünü inşa eden yapı.

Örnek bir proje üzerinden Builder Design Pattern'i implement etmeye çalışalım. Apple fabrikasında Iphone modelleri üretimi yapan bir senaryo yazalım ve bunu pattern'imizi uygulayarak yapmaya çalışalım.

Öncelikle ürün class'ımızı oluşturalım. Iphone'un farklı modellerini (6, 6S, SE, vs.) ürettiğimizi düşünelim ve constractor seviyesinde hangi modeli ürettiğimiz bilgisini verelim.

    //Product'ımız   
    public class Iphone
    {
        string phoneType;
        public Iphone(string phoneType)
        {
            this.phoneType = phoneType;
        }
    }

Şimdi ise Builder gibi davranan abstract class'ımızı oluşturalım. Bu class üretimde kullanacağımız abstract üyeler içerecektir. Icerisinde BuildOS ve BuildDevice adında iki abstract metot ve hangi iphone modelini üreteceği bilgisinin olacağı Iphone tipinde olan obje olacaktır.

    //abstract Builder nesnemiz   
    public abstract class IphoneBuilder
    {
        public abstract void BuildOS();

        public abstract void BuildDevice();

        Iphone IphoneType { get; }
    }

Sırada Builder class'larını geliştirme var. 6sBuilder ve SeBuilder adında iki tane iphone modeli için geliştirme yapalım.

SeBuilder

    // SE modeli için kullanacağımız Concrete Builder class'ımız
    public class SeBuilder : IphoneBuilder
    {
        Iphone device;

        public SeBuilder()
        {
            device = new Iphone("Se");
        }

        public override void BuildOS()
        {
            //TODO
        }

        public override void BuildDevice()
        {
            //TODO
        }

        public Iphone IphoneType
        {
            get { return device; }
        }
    }

_6sBuilder

   // 6S modeli için kullanacağımız Concrete Builder class'ımız
   public class _6SBuilder : IphoneBuilder
    {
        Iphone device;

        public _6SBuilder()
        {
            device = new Iphone("6S");
        }

        public override void BuildOS()
        {
            //TODO
        }

        public override void BuildDevice()
        {
            //TODO
        }

        public Iphone IphoneType
        {
            get { return device; }
        }
    }

Şimdi sırada üretim var. Manufacturer adında üretici class'ımızı oluşturalım.

   //Director class'ımız
   public class Manufacturer
    {
        public void Build(IphoneBuilder iphoneBuilder)
        {
            iphoneBuilder.BuildDevice();

            iphoneBuilder.BuildOS();
        }
    }

Sıra yaptığımız implementasyonu kullanmaya geldi. 

	public static void Main()
	{
		 Manufacturer manufacturer = new Manufacturer();

         _6SBuilder _6s = new _6SBuilder();

         manufacturer.Build(_6s);
	}

Main fonksiyon içerisinde Manufacturer'ı kullanarak _6s modelini build ettik. Builder pattern'nini elimizden geldiğince projemize entegre ettik ve diğer iphone ürünleri için de aynı akışı kullanarak ürünlerimizi Build edebiliriz.

Builder pattern'i factory ve abstract factory pattern'leri ile birçok yönden benzerlikler göstermektedir. Hangisini kullanmalıyım diye tereddütte kaldığınız durumlarda, complex objeler yaratıyorsanız Builder'ı, tek bir obje yaratmak istiyorsanız da factory veya abstract factory design pattern'i tercih edebilirsiniz.

Repository Design Pattern

Çoğu yazılım uygulamasının belli mimari kurallar çerçevisinde farklı katmanlara ayrılarak geliştirilmesi beklenir ve buna n-tier architecture denir. N-tier architecture presentation tier, middle tier yada data tier gibi çeşitli katmanlardan oluşabilir. Presentation katmanında uygulamanızın UI tarafını ilgilendiren arayüzler bulunur, Middle katmanda business logic'i ilgilendiren geliştirmeler yapılır ve aynı zamanda database ile etkileşimde bu katmanda bulunur. Data katmanı ise uygulamanızdaki SQL Server, Oracle gibi database context'lerini içeren katmandır. Bu katman belkide uygulamadaki en önemli katmandır sebebi ise database. Data bizim için en önemli şey ve database'ler ile olan veri alış verişi işin en güvenlikli ve generic olması gereken yerlerin başında gelir.

Database varsa CRUD işlemi (Create, Read, Update, Delete) heralde olmazsa olmazdır ve data katmanı ile doğrudan business logic'in bulunduğu middle katman haberleşsin istenilmez ve bu durum bazen uygulamanızın büyüklüğüne göre çeşitli sorunlarda çıkartabilir. Repository pattern bu ihtiyacı karşılayan pattern olarak karşımıza çıkıyor ve temelde yaptığı iş ise business logic ile data access arasında arabulucu görevi görme.

Repository Pattern Faydaları

  • Maintainability (sonradan bakım kolaylılığı) arttırır,
  • Unit-test yapabilmemizi kolaylaştırır,
  • Esnek bir mimari uygulamamızı sağlar,
  • Yeni gelecek modüller veya istenilen değişiklikleri kolayca entegre edebilmeyi sağlar,
  • Domain driven development'ın önünü açar.

 

Repository Pattern Uygulaması

Şimdi örnek bir proje üzerinden Repository Pattern nasıl uygulanır görelim. Projeyi geliştirirken projenizde EntityFramework kurulu ve SampleDbContext adında bir database context'inizin olduğunu varsayarak ilerliyor olacağız.

1.Adım - IRepository adında CRUD işlemleri yapabilmemizi sağlayacak Generic bir interface metodlarını tanımlama.

public interface IRepository<T>  where T : class
    {
        IEnumerable<t> SelectAll();
        T SelectByID(object id);
        void Insert(T obj);
        void Update(T obj);
        void Delete(object id);
        void Save();
    }

2.Adım - BaseRepository adında Generic IRepository interface'inden implement olan class'ı oluşturma.

public abstract class BaseRepository<T> : IRepository<T> where T : class
    {
        private SampleDbContext db = null;
        private DbSet<t> table = null;
        public BaseRepository()
        {
            this.db = new SampleDbContext();
            table = db.Set<T>();
        }
        public BaseRepository(SampleDbContext db)
        {
            this.db = db;
            table = db.Set<T>();
        }
        public IEnumerable<T> SelectAll()
        {
            return table.ToList();
        }
        public T SelectByID(object id)
        {
            return table.Find(id);
        }
        public void Insert(T obj)
        {
            table.Add(obj);
        }
        public void Update(T obj)
        {
            table.Attach(obj);
            db.Entry(obj).State = EntityState.Modified;
        }
        public void Delete(object id)
        {
            T existing = table.Find(id);
            table.Remove(existing);
        }
        public void Save()
        {
            db.SaveChanges();
        }
    }

3.Adım - Employee adında örnek bir Entity tanımlama

public class Employee
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

 

4.Adım - BaseRepository den inherit olan Employee entity si için EmployeeRepository class'ını tanımlama

  public class EmployeeRepository : BaseRepository<Employee>
    {

    }

5.Adım - Yazmış olduğumuz EmployeeRepository'yi kullanmak

  void Main(string[] args)
        {
            var empRepository = new EmployeeRepository();
            empRepository.SelectAll();
        }

Projemiz hazır. Bundan sonra tanımlayacağınız entity'ler için EmployeeRepository de olduğu gibi Generic olarak yazmış olduğumuz BaseRepository'den türeyen Repository'ler tanımlayarak projeyi geliştirmeye devam edebiliriz.

Not : Bir rivayete göre Repository Design Pattern, Design Pattern ailesi içerisinde en çok kullanılan pattern olduğu söylenir.