Design patterns

Abstract Factory Pattern

The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.

The Abstract Factory Pattern:

provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Design principles:

  • Designs should be open for extension but closed for modification
  • Depend upon abstractions. Do not depend upon concrete classes
  • Dependency inversion principle – high-level components should not depend on low-level components, but both types should depend on abstractions
  • Variables should not hold references to concrete classes
  • Classes should not derive from concrete classes
  • Methods should not override implemented methods in base classes

The intent of Abstract Factory is to create families of related objects without having to depend on their concrete classes. By using an Abstract Factory client is decoupled from the specifics of the concrete products. That allows implementing different factories that produce products for different contexts. We can substitute different factories to get different behaviors. Very often methods of an Abstract Factory are implemented as factory methods.

How it works (code example):

public interface BunComponentsFactory {
	public Dough createDough();
	public Stuffing createStuffing();
	public AdditionalStuffing createAdditionalStuffing();
	public Dressing createDressing();
}

public class VegetarianBunComponentsFactory {
	public Dough createDough() {
		return new FullGrainDough();
	}
	public Stuffing createStuffing() {
		return new SpinachStuffing();
	}
		public Stuffing createAdditionalStuffing() {
		return new CurdStuffing();
	}
	public Dressing createDressing() {
		return new RoastedVegetables();
	}
}
public abstract class Bun {
	String name;
	
	Dough dough;
	Stuffing stuffing;
	Dressing dressing;
	
	abstract void prepare();
	
	void bake() {
		System.out.println("Bake for 30 minutes at 220C")
	}
	
	void setName(String name) {
		this.name = name;
	}
	
	String getName() {
		return name;
	}
}

public class VegetarianBun extends Bun {
	VegetarianBunComponentsFactory componentsFactory;
	
	public VegetarianBun(VegetarianBunComponentsFactory componentsFactory) {
		this.componentsFactory = componentsFactory;
	}
	
	void prepare() {
		System.out.println("Preparing components for " + name)
		dough = componentsFactory.createDough();
		stuffing = componentsFactory.createStuffing();
		dressing = componentsFactory.createDressing();
	}
}
public abstract class Bakery {
	public Bun orderBun (String sort) {
		Bun bun;
		bun = createBun(sort);
		bun.prepare();
		bun.bake();
		return bun;
	}
	abstract Bun createBun(String sort);
}

public class VeganBakery extends Bakery {
	protected Bun createBun (String sort) {
		Bun bun = null;
		BunComponentsFactory componentsFactory = new VegetarianBunComponentsFactory();
		if (sort.equals("vegetarian bun")) {
			bun = new VegetarianBun(componentsFactory);
			bun.setName("Vegetarian bun");
		}
	}
}

Let’s run it:

public class Bake {
	public static void main(String[] args) {
		Bakery veganBakery = new VeganBakery();
		Bun bun = veganBakery.orderBun("veggy");
		System.out.println(bun.getName() + " is baked");
	}
}

Leave a Reply

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