Abstract Factory Pattern

Bir başka creational tasarım kalıbı olan abstract factory pattern, factory pattern şablonuna çok yakın bir yaklaşım ile oluşturulmuştur. Factory üzerine fazladan bir soyutlama katmanı ekleyerek, abstract factory patterni uygulamak mümkündür. Bu kalıp, birden fazla factory sınıfının bir arada bulunması ve uygulamanın hangi factory ile iş yapacağını belirlemesinin giderek zorlaştığı durumları ele alır ve çözer.

Factory pattern için kullandığımız örneği, biraz daha farklı bir noktaya çekerek bu kalıp için de bir sorunu inceleyelim. Önceki yazımızda market teslimatlarını yaparken, seçilen teslimat yöntemlerinin soyutlanmasından bahsetmiştik. Bu yazımız için o teslimat yöntemlerini mümkün kılan araçların üretimine odaklanalım.

Varsayalım ki motorlu taşıtlar üreten bir fabrikamız var. Bu taşıtlar farklı amaçlar için üretiliyor olsun. Üretilen araç modelleri teslimat, eşya taşımacılığı gibi nispeten dayanıklılık isteyen meslek dallarında kullanıldığı gibi, ailelere hitap eden ve konforu ile öne çıkan amaçlar için de kullanılıyor olabilir. Nihayetinde bu fabrikanın çıktısı bir araç olacaktır. Dolayısı ile buradaki durum, müşteri perspektifinden araç almak iken, fabrika perspektifinden üretim süreçlerini doğru şekilde tasarlamaktır.

Bu örnek için iki ayrı başlığa odaklanacağım. Araçların rahatlığını belirleyen etmenin süspansiyon olduğunu varsayalım. Aile araçları daha rahat bir süspansiyonla üretiliyor olsun. Ticari ve aile araçlarının kasalarının da amaçlarına uygun olarak fark gösterdiğini varsayalım. Mesela ticari araçların arka camları yerine panel bir yapı olsun. Ancak aile araçları ise standart arka camlarla üretilmiş olsun. Elbette daha fazla parça üzerinden genişletilebilecek bu örneği aşağıdaki görüntü ile bir de görsel olarak temsil edelim.

Bu örnekte süspansiyonlar kendi aralarında benzerlik göstermektedir. Aynı şekilde araç gövdeleri de benzerlik gösterirler. Üretim açısından süreçleri bir yere kadar benzer olan bu parçalar, kodlama açısından da aynı yaklaşımı sergilememize müsaittir. O halde bunları birer interface ile temsil etmemiz akıllıca olacaktır. Peki üretime bir süreç olarak odaklandığımızda karşımıza neler çıkar? Esasen montaj hattı üzerinde önemli bir değişikliğe ihtiyacımız olmadığını söyleyebiliriz. O halde üretim de benzer şekilde bir yaklaşımla interface arkasına alınabilir durumdadır. Sadece ilgili araç tipi için, ilgili interface/implementasyon ikilisini kullandığımızdan emin olmamız gerekmektedir. Şimdi bu durumu şematize edelim ve şemaya uygun olarak kodumuzu yazmaya başlayalım.

Şema üzerinden kısa bir özet geçecek olursak;

  • Süspansiyon (Suspension) bir interface olarak gösterilmiştir ve iki ayrı implementasyonu vardır.
  • Araç kasası (Body) bir interface olarak gösterilmiştir ve iki ayrı implementasyonu vardır.
  • İş araçları ve aile araçları ilgili süspansiyon ve kasa implementasyonlarını kullanır.
  • Araç üretimi genel olarak iki ayrı parçanın montajı ile temsil edilmiştir. Bunu da VehicleFactory arayüzü ile tanımlamış durumdayız. Bir araç gövde ve süspansiyon ikilisinin birleşmesi ile oluşur.
  • Satış biriminin isteğine göre hangi factorynin kullanılacağını seçen bir FactoryProducer vardır. Bu kalıbın en can alıcı kısmı burasıdır. Zira fabrikaların fabrikasını bu parça temsil eder.

Eğer bu özet ile, çözdüğümüz sorun kafanıza oturmadıysa, şemanın ortasını elinizle kapatıp, aslında ortada bir factory pattern olduğuna dikkat etmenizi öneririm. Elinizi kaldırdığınızda ise bu factory pattern üzerine bindirilmiş başka bir factory daha olduğunu gözlemleyebilirsiniz. Şimdi uygulama kısmına geçelim.

public interface Body {

	void produceBody();
	
}


public class StandardBody implements Body {

	@Override
	public void produceBody() {
		System.out.println("StandardBody produced");		
	}

}


public class VanBody implements Body {

	@Override
	public void produceBody() {
		System.out.println("VanBody produced");		
	}

}
public interface Suspension {

	void produceSuspension();
}

public class StandardSuspension implements Suspension {

	@Override
	public void produceSuspension() {
		System.out.println("StandardSuspension produced");

	}

}

public class ComfortSuspension implements Suspension {

	@Override
	public void produceSuspension() {
		System.out.println("ComfortSuspension produced");

	}

}
public interface VehicleFactory {

	void produceSuspension();

	void produceBody();

}

public class FamilyVehicleFactory implements VehicleFactory {

	@Override
	public void produceSuspension() {
		System.out.print("FamilyVehicleFactory suspension -> ");
		Suspension suspension = new ComfortSuspension();
		suspension.produceSuspension();
	}

	@Override
	public void produceBody() {
		System.out.print("FamilyVehicleFactory body -> ");
		Body body = new StandardBody();
		body.produceBody();
	}

}

public class BusinessVehicleFactory implements VehicleFactory {

	@Override
	public void produceSuspension() {
		System.out.print("BusinessVehicleFactory suspension -> ");
		Suspension suspension = new StandardSuspension();
		suspension.produceSuspension();
	}

	@Override
	public void produceBody() {
		System.out.print("BusinessVehicleFactory body -> ");
		Body body = new VanBody();
		body.produceBody();
	}

}
public enum VehicleType {

	FAMILY,BUSINESS
}

public class FactoryProducer {

	public static VehicleFactory getFactory(VehicleType vehicleType) {

		VehicleFactory vehicleFactory;

		switch (vehicleType) {
			case FAMILY:
				vehicleFactory = new FamilyVehicleFactory();
				break;
			case BUSINESS:
				vehicleFactory = new BusinessVehicleFactory();
				break;
			default:
				vehicleFactory = new FamilyVehicleFactory();
				break;
		}

		return vehicleFactory;
	}
}

public class Production {

	public void produceVehicle(VehicleType vehicleType) {

		VehicleFactory factory = FactoryProducer.getFactory(vehicleType);
		factory.produceBody();
		factory.produceSuspension();
	}

}

Bu kısım tasarım kalıbımızın uygulanmış bir örneğidir. Bu kodların kullanımı adına bir test sınıfı yazalım ve iki ayrı araç tipini üretmek için kalıbımızın kullanımına göz atalım.

public class Test {

	public static void main(String[] args) {
		
		Production production = new Production();
		
		System.out.println("FamilyVehicle Production");
		production.produceVehicle(VehicleType.FAMILY);
		
		System.out.println("--------------------------");
		
		System.out.println("BusinessVehicle Production");
		production.produceVehicle(VehicleType.BUSINESS);
		
	}
}
Çıktı:
FamilyVehicleFactory body -> StandardBody produced
FamilyVehicleFactory suspension -> ComfortSuspension produced
BusinessVehicleFactory body -> VanBody produced
BusinessVehicleFactory suspension -> StandardSuspension produced

Yapısı gereği ile factory pattern ile büyük benzerlikler gösteren abstract factory tasarım kalıbımızı bitirmiş olduk. Bu kalıbın getirdiği avantajlar, kardeşi factory ile benzerlik gösterirken, dezavantaj noktasında da bir üst soyutlama katmanının bulunması sebebi ile daha kompleks sorunlara yol açmaya müsaittir. Dikkatinizi çekeceği üzere çok fazla interface ve implementasyon ile uğraşmak kodda anlaşılmayı zorlaştırabilmektedir. Buna karşın yeni parçaların eklenmesi uygulamanın belli bir noktasından sonrasını ilgilendirmez haldedir ve mevcut tüketicilere etki vermeden kod değişikliği yapmak mümkündür.

1 comment on Abstract Factory Pattern

Leave a Reply

Your email address will not be published. Required fields are marked *