Abstract Factory Method Tasarım Deseni

20 Mar

Factory Method tasarım deseni, nesne oluşturma ihtiyacı doğrultusunda ortaya çıkmış bir tasarım desenidir. Bu tasarım deseni, oluşturulacak somut nesnenin türünü belirlemeye gerek duymadan nesne oluşturma işlemini temel almaktadır.

Resim-1
Resim-1

Factory deseninin temel amacı nesne oluşturma karmaşıklığını kullanıcıdan gizlemektir. Ayrıca kullanıcı, oluşturulacak nesnenin somut türünü belirlemek zorunda değildir. Bunun yerine somut nesnenin implemente edildiği soyut tür olan interface veya abstract class tipini bilmesi yeterlidir. Yani sorumluluk somut nesnelerden soyut nesnelere aktarılmaktadır. Genel olarak Factory sınıflar “static” erişim belirleyicili bir metod barındırırlar. Bu metod, kullanıcıya interface veya abstract class tipinde bir nesne döndürür. Bu sayede kullanıcılar, alt sınıfların oluşturulması sorumluluğundan dolayı oluşabilecek hatalardan da uzak tutulmuş olur.

Örnek Uygulama

Bu örnek uygulamamızda Grafik türüne göre Grafiğin temsilini yapan Sembollerin oluşturulmasını Factory Method yöntemiyle üretmeyi amaçlamaktayız.

Yukarıdaki şekildeki tasarım deseninin uygulanışını şu şeklide yapabiliriz.

Resim - 2
Resim – 2

Gerçek bir uygulamadan alarak göstereceğim bu örnekte bir REST servisinden gelen Graphic nesnesinin türüne göre sembol nesnesinin belirlenmesi işlemini Factory Method inceleyeceğiz. Tabi bu örnekteki konumuz Factory uygulaması olduğundan Servis işlemlerini temsili olarak göreceğiz. Bizi ilgilendiren sadece nesne üretimi olduğundan nesne üretim aşamasını inceleyeceğiz.

   public class Graphic
   {
      public Symbol Symbol { get; set; }
   }

Bize servis tarafından sunulan Graphic nesnesi Null olarak gelmektedir. Biz yazılım tarafında Graphic nesnesinin türüne göre Sembolünü üretmekle sorumluyuz.

public abstract class Symbol
{
     public abstract void draw();
}

Symbol sınıfının soyut bir tip olduğunu görüyoruz. Graphic sınıfında da bu soyut tip kullanılmıştır.

public class SimpleLineSymbol: Symbol
{
    public override void draw()
    {
       // Draw line
    }
}

public class SimpleFillSymbol: Symbol
{
     public override void draw()
     {
       // Draw polygon
     }
}

public class SimpleMarkerSymbol: Symbol
{
    public override void draw()
    {
       // Draw point
    }
}

Somut sembol sınıfları ise SimpleLineSymbol, SimpleFillSymbol, SimpleMarkerSymbol şeklinde oluşturulmuştur.

public class GraphicSymbolFactory
{
    public static Symbol GetSymbol(Graphic graphic)
    {
        if(graphic is Point)
           return new SimpleMarkerSymbol();
        if(graphic is Polygon)
           return new SimpleFillSymbol();
        if(graphic is Polyline)
           return new SimpleLineSymbol();

        throw new InvalidExpressionException("Unknown graphic type");
    }

}

GraphicSymbolFactory sınıfına eklediğimiz GetSymbol metodu, Graphic türüne göre somut olan Symbol tiplerini oluşturmaktadır. Dikkat edecek olursak kullanıcıya soyut olan bir Symbol tipi vermekteyiz. Yani içerde olup bitenden kullanıcılar haberdar değildir.

public class GraphicService
{
    private readonly IGraphicRestService service;

    public GraphicService(IGraphicRestService service)
    {
       this.service = service;
    }

    public Graphic GetGraphicsFromRESTService(string serviceUrl)
    {
       Graphic graphic = service.GetGraphic(serviceUrl);

       graphic.Symbol = GraphicSymbolFactory.GetSymbol(graphic);

       return graphic;
    }

}

GraphicService sınıfı içerisinde tanımlı GetGraphicsFromRESTService metodu, bir servis yardımıyla Graphic nesnesini elde etmektedir. Gelen Graphic nesnesinin sembolü ise kullanıcı tarafından Factory sınıfı yardımıyla belirlenir. Burada kullanıcı diye adlandırdığımız GraphicService sınıfıdır aslında. Çünkü API içerisinde hazırladığımız GraphicSymbolFactory tipini kullanan sınıftır. Kullanıcı sınıf aslında Symbol tipinden türetilen SimpleLineSymbol veya SimpleFillSymbol gibi tiplerden haberdar değildir. Bu somut tipleri oluşturmak zorunda da değildir. Bu karmaşık sorumluluğu Factory deseni ile bir sınıfa aktarmış olduk.

Bir başka yazıda görüşmek dileğiyle.