Factory ve Abstract Factory Tasarım Kalıpları

Yazılım tasarım kalıpları (software design patterns) ya da şablonları kavramı, yazılım geliştirmede tasarımda sıklıkla karşılaşılan problemlere getirilen tekrar kullanılabilir genel çözümler olarak tanımlanabilir tabi burada bu çözümlerin sadece OOP için değil diğer yazılım geliştirme yaklaşımlarında da bir takım uygulamaları olduğunu unutmamak gerekir. Tasarım kalıplarını direk olarak koda donüştürülüp çalıştırılan bir yapı olarak düşünmemek gerekir, tasarım kalıpları daha çok dizayn ile ilgilidir, yazılım tasarımında karşılaşılan problemlerin çözümüne yönelik “best practise” leri içerir. Konunun tarihçesinden bir kaç cümle ile bahsetmek gerekirse bilgisayar bilimlerinde tasarım kalıplarının popularite ve ivme kazanması 1994 te “gang of four” olarak bilinen 4 yazarın (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides) eseri olan  Design Patterns : Elements of Reusable Object-Oriented Software isimli kitap ile başlamıştır. Değişen ihtiyaçlar ile birlikte bir çok farklı kalıplar zaman içerisinde ortaya çıkmıştır, var olanlara ihtiyaçlar dahilinde farklı bakış açıları getirilmiştir.

Genel olarak tasarım kalıpları

  • Creational Patterns  (Oluşturucu Kalıplar)
  • Structural Patterns   (Yapısal Kalıplar)
  • Behavioral Patterns (Davranişsal Kalıplar)

olarak ayrılır, mumkun olduğunca bu başlıkların altında tanımlanmış tüm design pattern lerine değinmeye çalışacağım. Gerçek hayata yakın kod örnekleri ile pattern in pratik uygulamasını da yapmaya çalışacağım. Şimdi bu genel başlıklar altında yer alan pattern ler neler göz atalım

      Creational Patterns (Oluşturucu Tasarım Kalıpları)

  • Factory
  • Abstract Factory
  • Builder
  • Prototype
  • Object Pool
  • Singleton

      Structural Patterns (Yapısal Tasarım Kalıpları)

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Front Controller
  • Module
  • Proxy

      Behavioral Patterns (Davranışsal Tasarım Kalıpları)

  • Chain of Responsibility
  • Command
  • Mediator
  • Memento
  • Observer
  • Strategy
  • Template
  • Visitor

Konuyu OOP tasarım paradigması içerisinde değerlendiriyor olacağız, implementasyonlar java dilinde olacak. Konuya girmeden önce sıklıkla karşımıza çıkacak bazı UML (Unified Modeling Language) notasyonlarından kısaca bahsetmek istiyorum, UML geniş bir konu olduğu için burada UML`in bütün detaylarına girmek mümkün değil, temel notasyonlardan bahsedeceğim. UML notasyonları konuyu top view olarak hızlıca görmemizi ve kavramamızı kolaylaştıracaktır. Esasında tasarım dendiğinde bunu UML den ayrı düşünmek mümkün değildir, çünkü tasarımı UML notasyonu ile göstermekteyiz. Tasarımımızı  diğer geliştiricilerle, proje grubuyla v.s paylaşmak istersek bunu ancak UML ile yapabiliriz. UML tasarimimizin dökümante edilmesinde de kolaylık sağlayacaktır. UML aslında tasarımımızın dili olmaktadır, zaten “modeling language” dir. Tasarım kalıpları özelinde bize lazım olacak temel UML gösterimleri ile devam edelim.

Temel UML Gösterimleri

Class Diagram (Sınıf Diyagramı)

Sınıfı gösteren diyagramdır, sınıfın attribute leri, metodları v.s. bu diyagram üzerinde gösterilir.

Abstract Class Diagram (Soyut Sınıf Diyagramı)

Abstract bir sınıfı belirtmek için sınıf diyagramında sınıf ismi italik olarak yazılır.

Inheritance (Türeme)

OOP nin temel kavramlarından birisi olan inheritance özelliğinin UML ile gösterim biçimidir. İçi boş ok çizgisi ile gösterilir, okun baş kısmı inherit edilen sınıfı (super class) işaret eder.

Interface (Arayüz)

Aggregation

Bir sınıf (child class – professor) başka bir sınıfin (parent class – faculty) bir parçası ise ve parent sınıf olmadan da bu sınıfin instance ları yaşayabiliyorsa bu tarz ilişkiye aggregation denir..

Composition

Aggregation ‘ın tersine eğer child sınıfın instance’larının yaşamları parent sınıfın instance’ının yaşıyor olması ile ilişkili ise yani parent sınıf olmadan bu instance’lar tek başına var olamıyorlarsa bu tarz ilişkiye composition ismi verilir.

Bahsedilen notasyonlar teml UML diyagramlarıdır.

Factory Design Pattern (Fabrika Tasarım Kalıbı)

Aşağıdaki lojik ile öncelikle bu tasarim kalibinin daha kolay anlaşılması için gerekli temel notasyonu inceleyelim.

Öncelikle bu pattern creational(oluşturucu) bir pattern dir, geliştirdiğimiz yazılımlarda sıklıkla oluşturduğumuz nesnelerin oluşturulma sürecini belirli bir lojik ile ele alarak daha düzgün bir tasarım oluşturmamıza olanak verir. Hedefi nesnelerin oluşturulmasına yönelik bir tasarım önerisi sunmaktır.

Client olan nesne Factory nesnesini kullanarak ihtiyacı olan Product nesnesini elde eder. Yani java ile örneklendirirsek new ile başlayan nesne oluşturma sürecini daha organize ve tekrar kullanılabilir bir hale getirir. İstenen tipte yeni nesne oluşturma sürecinin Factory sınıfına aktarılması ile birlikte nesne üretme ve initialize etme süreci client tan soyutlanmış olur, bu sayede client; uygulama içerisinde tamamen kendi rolüne odaklanmış olur, çünkü yeni nesnenin nasıl oluşturulacağına dair detaylardan soyutlanmış olur, bunları bilmek zorunda değildir. Bu pattern in tam anlamıyla Client’in Product oluşturma işleminden soyutlanmasını sağlayabilmesi için Client’in oluşturulacak Product tipinden ve bu Product’ı oluştururken kullanılacak olan Factory tipinden soyutlanmış olması gerekir. Tabi bunu sağlamanın yolu interface kullanmaktır. Pattern genel olarak;

  • istenen tipte nesne oluşturma sürecini Client’ın bu konuda detay bilgi sahibi olmadan gerçekleştirilmesini sağlar
  • yeni oluşturulan nesneye bir interface ile referans edilerek ulaşılmasını sağlar

Aşağıda pattern’in UML olarak gösterimi konuyu daha net ifade etmektedir.

Client, Factory den kendisine IProduct tipinde bir instance (ConcreteProduct) oluşturup vermesini ister, Factory bu nesneyi nasıl oluşturacagını bilmektedir ve nesneyi oluşturup initialize edip isteyen Client’a bu nesneyi döndürür.

Şimdi çok temel olan bu ilk yaklaşımı bir kod parçası ile örneklendirelim.

public interface IProduct
{
       public String getProductName();

       public String getProductSerialNumber();

       public Date getProductionDate();
}
public class Product implements IProduct
{     
       private final String _serialNumber;
       private Date _productDate;

       public Product(String serialNumber)
       {
             _serialNumber = serialNumber;
             _productDate = new Date();
       }

       @Override
       public String getProductName()
       {
             return "i am product";
       }

       @Override
       public String getProductSerialNumber()
       {
             return _serialNumber;
       }

       @Override
       public Date getProductionDate()
       {
             return _productDate;
       }     
}
public class ProductFactory
{
       /**seri numarasinin sequential artan bir numara oldugunu varsayalim*/
       private static int _serialNumber = 0;

       public IProduct makeProduct()
       {
             String serialNumber = generateSerialNumber();
             return new Product(serialNumber);
       }

       private String generateSerialNumber()
       {
             return (++_serialNumber)+"";
       }
}
public final class ProductClientA
{
       public ProductClientA()
       {
       }

       public void doSomeClientAJob()
       {
             IProduct product = new ProductFactory().makeProduct();

             System.out.println("Product Name -> "+product.getProductName());

             System.out.println("Product Serial Number -> "+

                                 product.getProductSerialNumber());
       }
}
public final class ProductClientB
{
       public ProductClientB()
       {
       }

       public void doSomeClientBJob()
       {
             IProduct product = new ProductFactory().makeProduct();

             System.out.println("Product Name -> "+product.getProductName());

             System.out.println("Product Serial Number -> "+
                                 product.getProductSerialNumber());
       }
}
public final class Main
{
       public static void main(String[] args)
       {
             ProductClientA pcA = new ProductClientA();
             pcA.doSomeClientAJob();
         
             ProductClientB pcB = new ProductClientB();
             pcB.doSomeClientBJob();
       }
}

Yukarıdaki kod örneğinde programımızda iki farklı sınıfta (ProductClientA ve ProductClientB) Product oluşturma ihtiyacı var, bu ihtiyaç ilgili Factory sınıfı üzerinden yapılmaktadır.

Eğer Factory kullanmamış olsaydık kodumuzda Product oluşturmak istediğimiz her noktada new Product(….) gibi bir kod kullanacaktık, üstelik initialization parametrelerini de vermemiz gerekecekti, bu da Client’in Product hakkında çok fazla bilgi sahibi olmasına neden olacaktı ki bu bilgilerin bir kısmına Product oluştururken hiç ihtiyacı olmayacak. Üstelik client’ın Product’ın ihtiyaç duyduğu serial number parametresini de geçmesi gerekiyor ki bunun nasıl generate edileceğini client’ın bilmesini gerektirir bu durum, oysa client bununla kesinlikle ilgili değildir, client’ın istediği düzgün init edilmiş bir Product nesnesidir.

Şimdi ayni örnek üzerinden başka bir senaryoyu düsünelim, Product’ımızı bir Factory ile değil de ihtiyaç duyduğumuz yerlerde new() ile oluşturduğumuzu varsayalım, bir süre sonra Product’ımıza yeni bir property ekleme ihtiyacı ortaya çıktığını ve bu property’nin kesinlikle Product constructor üzerinden initialize edilmesi gerektiğini varsayalım. Bu durumda tüm new Product() yapılan yerleri bulup bu yeni property için uygun değeri geçmeye başlayacağız ki bu hoş olmayan ve bir çok problemlere neden olabilecek bir durumdur. Yani ProductClientA,ProductClientB sınıfları ve daha nerelerde kullanılıyorsa onları bulup değiştirmek gerekecektir. Oysa Factory kullanıldığında yapılacak tek şey Factory üzerinde Product’i oluşturan metotta gerekli değişikliği yapmak olacaktır.

Buraya kadar pattern’i en önemli özellikleriyle anlatacak steril örnekler üzerinden hareket ettik, simdi biraz daha gerçek hayat problemlerini isin içine katmaya çalışalım. Çoğu zaman elimizde tek bir Product değil bir çok Product bulunur, birden fazla Product olduğunda Factory’yi nasıl uygulayacağız. Öncelikle bu durum ile ilgili UML diyagramımıza bir göz atalım.

Diyagramda gösterildiği üzere iki adet IProduct implement eden sınıfımız var, ConcreteProductOne ve ConcreteProductTwo; simdi Factory miz kendisine geçilen bir String parametreyi kontrol ederek hangi Product’ı oluşturacağına karar verecek ve oluşturup Client’a geri döndürecektir. Basit olarak bu durumu kodlayalım ve bu yöntemin istediğimiz esnekliği, OOP tasarım prensiplerini sağlayıp sağlamadığını gözden geçirelim.

public interface IProduct
{
       public String getProductName();

       public String getProductSerialNumber();

       public Date getProductionDate();
}
public class ProductOne implements IProduct
{
       private final String _productName = "ProductOne";
       private final String _serialNumber;
       private Date _productDate;
      
       public ProductOne(String serialNumber)
       {
             _serialNumber = serialNumber;
             _productDate = new Date();
       }
      
       @Override
       public String getProductName()
       {
             return "i am " + _productName;
       }

       @Override
       public String getProductSerialNumber()
       {
             return _serialNumber;
       }

       @Override
       public Date getProductionDate()
       {
             return _productDate;
       }
}
public class ProductTwo implements IProduct
{
       private final String _productName = "ProductTwo";
       private final String _serialNumber;
       private Date _productDate;

       public ProductTwo(String serialNumber)
       {
             _serialNumber = serialNumber;
             _productDate = new Date();
       }
      
       @Override
       public String getProductName()
       {
             return "i am " + _productName;
       }

       @Override
       public String getProductSerialNumber()
       {
             return _serialNumber;
       }

       @Override
       public Date getProductionDate()
       {
             return _productDate;
       }
}
public class ProductFactory
{
       /**seri numarasinin sequential artan bir numara oldugunu varsayalim*/
       private static int _serialNumber = 0;
      
       public IProduct makeProduct(String productType) throws IllegalArgumentException
       {           
             if(productType.equals("One"))
             {
                    String serialNumber = generateSerialNumber();
                    return new ProductOne(serialNumber);
             }
             else if(productType.equals("Two"))
             {
                    String serialNumber = generateSerialNumber();
                    return new ProductTwo(serialNumber);
             }
             else
                    throw new IllegalArgumentException("unsupported type");
       }
      
       private String generateSerialNumber()
       {
             return (++_serialNumber)+"";
       }
}
public final class ProductClient
{
       public ProductClient()
       {
       }
      
       public void doSomeClientJob()
       {
             try
             {
                    IProduct product = new ProductFactory().makeProduct("One");
                    System.out.println("Product Name -> "+product.getProductName());
                    System.out.println("Product Serial Number -> "+
                                      product.getProductSerialNumber());
                   
                    product = new ProductFactory().makeProduct("Two");
                    System.out.println("Product Name -> "+product.getProductName());
                    System.out.println("Product Serial Number -> "+
                                     product.getProductSerialNumber());
             }
             catch(IllegalArgumentException e)
             {
                    e.printStackTrace();
             }
       }
}
public final class Main
{
       public static void main(String[] args)
       {
             ProductClient pc = new ProductClient();
             pc.doSomeClientJob();
       }
}

Bu tasarımın önceki tasarımdan farkı Factory sınıfımızın, IProduct oluşturan metoduna geçilen parametrenin değerine bakarak hangi Product’i oluşturacağına karar vermesi, burada if else yerine bir switch case yapısı da kullanılabilirdi, ya da String yerine int tipte bir id v.s. geçilebilirdi içerideki seçme lojik i çok önemli değil. Burada öncelikle şunu söyleyelim eğer bir üçüncü product (ProductThree) ileride dahil edilmek istenirse yapılacak şey gidip içerideki seçme lojik ine bir durum daha eklenmesi olacak, bize bu esnekliği sağlıyor. Ancak buradaki problem Factory sınıfının kendisinin OOP deki open-closed yani “open for extension closed for modification” prensibine uymuyor olması, çünkü her yeni Product eklediğimizde Factory sınıfını baştan değiştireceğimiz anlamına geliyor bu. Bunun yerine Reflection ve Enum yapısından faydalanarak bir çözüm üretebiliriz.

public interface IProduct
{
       public String getProductName();
     
       public String getProductSerialNumber();
      
       public Date getProductionDate();
}
public class ProductOne implements IProduct
{
       private final String _productName = "ProductOne";
       private final String _serialNumber;
       private Date _productDate;
      
       public ProductOne(String serialNumber)
       {
             _serialNumber = serialNumber;
             _productDate = new Date();
       }
      
       @Override
       public String getProductName()
       {
             return "i am " + _productName;
       }

       @Override
       public String getProductSerialNumber()
       {
             return _serialNumber;
       }
 
       @Override
       public Date getProductionDate()
       {
             return _productDate;
       }
}
public class ProductTwo implements IProduct
{
       private final String _productName = "ProductTwo";
       private final String _serialNumber;
       private Date _productDate;
      
       public ProductTwo(String serialNumber)
       {
             _serialNumber = serialNumber;
             _productDate = new Date();
       }
      
       @Override
       public String getProductName()
       {
             return "i am " + _productName;
       }
 
       @Override
       public String getProductSerialNumber()
       {
             return _serialNumber;
       }

       @Override
       public Date getProductionDate()
       {
             return _productDate;
       }
}
public enum EnumProduct
{
       PRODUCT_ONE(ProductOne.class.getName(),ProductOne.class),
       PRODUCT_TWO(ProductTwo.class.getName(),ProductTwo.class);
      
       private final String _productClassName;
       private final Class<?> _classType;
      
       private EnumProduct(String productClassName, Class<?> classType)
       {
             _productClassName = productClassName;
             _classType = classType;
       }
 
       public String getProductClassName()
       {
             return _productClassName;
       }
 
       public Class<?> getClassType()
       {
             return _classType;
       }
}
public class ProductFactory 
{
	/**seri numarasinin sequential artan bir numara oldugunu varsayalim*/
	private static int _serialNumber = 0;
	
	public IProduct makeProduct(EnumProduct productType) throws Exception
	{	
		try
		{
			String serialNumber = generateSerialNumber();
			
			return (IProduct) Class.forName(productType.getProductClassName())
		      .getConstructor(String.class).newInstance(serialNumber);
		}
		catch(Exception e)
		{
			throw e;
		}
	}
	
	private String generateSerialNumber()
	{
		return (++_serialNumber)+"";
	}
}
public final class ProductClient 
{
	public ProductClient()
	{
	}
	
	public void doSomeClientJob()
	{
		try
		{
			IProduct product = 
                   new ProductFactory().makeProduct(EnumProduct.PRODUCT_ONE);
			System.out.println("Product Name -> "+product.getProductName());
			System.out.println("Product Serial Number -> "+
			                    product.getProductSerialNumber());
			
			product = new ProductFactory().makeProduct(EnumProduct.PRODUCT_TWO);
			System.out.println("Product Name -> "+product.getProductName());
			System.out.println("Product Serial Number -> "+
			                    product.getProductSerialNumber());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
public final class Main 
{
	public static void main(String[] args) 
	{
		ProductClient pc = new ProductClient();
		pc.doSomeClientJob();
	}
}

Yukarıdaki çözümde yeni bir Product sisteme dahil edilirse yapmamız gereken şey Enum üzerinde gerekli tanımlamayı yapmak olacaktır, Factory sınıfı üzerinde herhangi bir değişiklik yapma ihtiyacı olmayacak.

Peki konuyu biraz daha gerçek hayatın içine çekerek daha karmaşık bir problemi düşünelim, çoğu zaman Product’larımız aynı şekildeki constructur’lara sahip olmayacaktır. Bu senaryoyu şöyle bir örnekle açıklayalım, şekilleri çizdirdiğimizi düşünelim, dikdörtgen, daire, elips v.s. her bir çizim seklimiz bir çizim noktasına (origin) sahip olsun ve bu nokta referans alınarak çizim yapılsın, eğer dikdörtgen ise bu noktadan itibaren genişlik ve yükseklik kadar çizim yapılırken bir daire ise bu defa da verilen noktadan itibaren yarıçap kadar çizim yapılsın. Dörtgen oluştururken genişlik ve yükseklik bilgisi lazım olurken daire oluştururken sadece yarıçap bilgisi yeterli olacaktır, bu tasarımı Factory pattern’i içerisinde nasıl ele alabiliriz. Normalde bunun çözümü için Abstract factory design pattern bir çözüm olabilir, ancak başka bir çözüm olarak da concrete shape sınıflarını initialize eden parametrelerin bir parametre interface’i üzerinden sınıflara geçilmesi şeklindedir, her bir shape kendi initializer sınıfını constructor ından parametre olarak alıp bu nesne üzerinden kendisi için gerekli bulunan initialize parametrelerini okuyabilir.

Abstract Factory Design Pattern (Soyut Fabrika Tasarım Kalıbı)

Factory tasarım kalıbında nesnelerin oluşturulması için gerekli bilgi ve sorumluluk client tan mümkün olduğunca alınmaya calışılmaktaydı, Abstract Factory tasarım kalıbı ise farklı Product’lar üreten Fabrika’ların soyutlanması fikri üzerine kurulu bir tasarım kalıbıdır. Öncelikle pattern’in UML diyagramına bir göz atalım.

UML diyagramı yukarıdaki şekildedir, daha gerçek hayattan örnekler üzerinden hareket ederek konuyu somutlaştırmaya çalışalım, örneğin arabalar için parça üreten bir fabrika olduğunu düşünelim, bu fabrikanın farklı araba markaları için lastik ve ön far ürettiğini varsayalım. Şimdi bu senaryoyu UML kullanarak pattern’in yukarıda verilen genel kuralları ile modelleyelim.

Factory sınıfımız abstract bir sınıftır, birbiriyle benzer nesneleri (bu örnekte lastikler kendi içinde ve farlar kendi içinde benzerdir) oluşturmak için ortak bir arayüz sağlar. Aslında nesne fabrikalarını soyutlayan bir yapı olmaktadır. Eğer ileride bu fabrika Volkswagen için de ön far ve lastik üretmeye başlarsa yapılacak şey bir concrete factory’nin (audi ve mercedes te olduğu gibi) daha sisteme dahil edilmesidir.

public abstract class Tire 
{
	protected final String _tireModel;
	
	public Tire(String tireModel)
	{
		_tireModel = tireModel;
	}
	
	public String getTireModel()
	{
		return _tireModel;
	}
}
public class AudiTire extends Tire 
{
	public AudiTire()
	{
		super("audi tire");
	}
}
public class MercedesTire extends Tire 
{
	public MercedesTire()
	{
		super("mercedes tire");
	}
}
public abstract class HeadLight 
{
	protected final String _headLightModel;
	
	public HeadLight(String headLightModel)
	{
		_headLightModel = headLightModel;
	}
	
	public String getHeadLightModel()
	{
		return _headLightModel;
	}
}
public class AudiHeadLight extends HeadLight 
{
	public AudiHeadLight()
	{
		super("audi headlight");
	}
}
public class MercedesHeadLight extends HeadLight 
{
	public MercedesHeadLight()
	{
		super("mercedes headlight");
	}
}
public abstract class Factory 
{
	public abstract Tire makeTire();
	
	public abstract HeadLight makeHeadLight();
}
public class MercedesFactory extends Factory 
{
	@Override
	public Tire makeTire() 
	{
		return new MercedesTire();
	}

	@Override
	public HeadLight makeHeadLight() 
	{
		return new MercedesHeadLight();
	}
}
public class AudiFactory extends Factory 
{
	@Override
	public Tire makeTire() 
	{
		return new AudiTire();
	}

	@Override
	public HeadLight makeHeadLight() 
	{
		return new AudiHeadLight();
	}
}
public class FactoryMaker 
{	
	public static Factory getFactory(String factoryName)
	{
		if(factoryName.equals("audi"))
			return new AudiFactory();
		else if(factoryName.equals("mercedes"))
			return new MercedesFactory();
		else
			return null;
	}
}
public class Client 
{
	public void doSomeClientJob()
	{
		Tire tire = FactoryMaker.getFactory("audi").makeTire();
		System.out.println(tire.getTireModel());
		HeadLight light = FactoryMaker.getFactory("audi").makeHeadLight();
		System.out.println(light.getHeadLightModel());
	}
}
public final class Main 
{
	public static void main(String[] args) 
	{
		Client client = new Client();
		client.doSomeClientJob();
	}
}

Factory bize concrete bir nesne değil de concrete nesneye point eden bir abstract pointer döndürdüğü için client, concrete nesne tipi hakkında bilgi sahibi olmak zorunda değildir. Client concrete sınıfa bir abstract pointer üzerinden ulaşmakta, dolayısıyla low coupling ilkesi açısından önemli bir kazanım.

Yeni bir concrete tip eklemek istersek yani VolkswagenFactory gibi, sadece client kodunda güncelleme yapmak gerekecek.

Abstract factory pattern’i ilişkili nesne gruplarının ortak bir arayüz üzerinden erişimine olanak sağlamaktadır. Abstract factory pattern’inin iyi yönleri yanında problemli yönleri de mevcuttur, nesne oluşturmayı client’tan mümkün olduğunca soyutlar, client; instance’lara bir abstract sınıf aracılığı ile erişir. Ancak bu yöntemin bir dezavantajı yeni bir Product sisteme eklenmek istendiğinde, yani bu örnekte fabrika audi ve mercedes için bir de araba camı üretmek isterse yeni ürünü sisteme eklemek için Factory abstract sınıfında deşişiklik yapmak gerekir ki bu da Factory den türeyen tüm alt sınıflarda da değişiklik yapılması anlamına gelir. Ayrıca her bir ürün ailesi için (far,lastik) farklı concrete factory sınıflar oluşturduk, eğer çok fazla ürün ailesi söz konusu ise birbirinden çok küçük farklar ile ayrılsalar bile her bir Product için yeni bir factory alt sınıfı oluşturmak gerekecektir.

Fabrikaları singleton olarak tanımlamak mantıklıdır, çünkü yazılımda bir tipte sadece bir concrete  factory olması (örneğin AudiFactory) ve instance’ların bu singleton nesne üzerinden oluşturulmaları gibi.

3 Comments
  • Posted at 16:16, 05/02/2016

    hocam bilgiler için çok sağolun önere bileceğiniz bi kaynak kitap varmıydı acaba dizayn patternle ilgili

  • Emir
    Posted at 19:04, 07/08/2016

    Çok güzel ve kapsamlı bir yazı olmuş. Teşekkürler.

  • celal
    Posted at 18:45, 14/02/2017

    Böyle değerli bir paylaşımı reytinge kurban edilmemesi için, tasarım desenleri ile ilgili yazılarınızı bekliyoruz açıkçası. Resmen şiir gibi akip gitti…Diğer yazılarınızı baktim ama malesef bi bu imiş… Çok teşekkürler.

Bir Cevap Yazın