Overview

Abstract factory is a creational pattern that lets you produce familes of related objects without specifying their concrete classes.

Advantages

  • Ensures that all products from the same factory are compatible with each other.
  • Avoid coupling between concrete products and client code.
  • Satisfies single responsibility principle as product creation code is extracted into one place.
  • Satisfies open/closed principle as new variants of products can be introduced without breaking existing client code.

Disadvantages

  • Code becomes more complex with introduction of interfaces and classes.

Applicability

  • When the code needs to work with various families of related products, but we don’t want it to depend on the concrete classes of these products - these might be unknown beforehand or we want to allow for future extensibility. Objects created via a factory are designed to be compatible with other objects created by the same factory.

Example

interface Button {
    public void setLabel(String labelText);
    public void click();
}

interface CheckBox {	
	public void setText(String text);
	public String getText();

	public void setStatus(boolean status);
	public boolean getStatus();	
}

// Abstract factory interfaces declares a set of methods that
// return different abstract objects. These products together
// form a product family.
interface GUIFactory {
    Button getButton(); 
    CheckBox getCheckBox();
}

class ButtonLinux implements Button {
    private String labelText = "";

	@Override
	public void setLabel(String labelText) {
		this.labelText = labelText;
		System.out.println("ButtonLinux: Setting label " + labelText);
	}

	@Override
	public void click() {
		System.out.println("ButtonLinux: clicking button with label " + this.labelText);	
	}
}

class ButtonWin implements Button {
    private String labelText = "";

	@Override
	public void setLabel(String labelText) {
		this.labelText = labelText;
		System.out.println("ButtonWin: Setting label " + labelText);
		
    }

	@Override
	public void click() {
		System.out.println("ButtonWin: clicking button with label " + this.labelText);
	}
}

class CheckBoxLinux implements CheckBox {
	private String text = "";
	private boolean status = false;
	
	@Override
	public void setText(String text) {
		this.text = text;
		System.out.println("CheckBoxLinux: Setting Text " + this.text);

	}

	@Override
	public String getText() {
		return this.text;
	}	
	
	@Override
	public void setStatus(boolean status) {
		this.status = status;
		System.out.println("CheckBoxLinux: setStatus status " + this.status);

	}

	@Override
	public boolean getStatus() {
		return this.status;
	}
}

class CheckBoxWin implements CheckBox {
	private String text = "";
	private boolean status = false;
	
	@Override
	public void setText(String text) {
		this.text = text;
		System.out.println("CheckBoxWin: Setting Text " + this.text);
	}

	@Override
	public String getText() {
		return this.text;
	}	
	
	@Override
	public void setStatus(boolean status) {
		this.status = status;
		System.out.println("CheckBoxWin: setStatus status " + this.status);
	}

	@Override
	public boolean getStatus() {
		return this.status;
	}
}

// A Linux Factory can produce a Linux button and a Linux checkbox.
class GUIFactoryLinux implements GUIFactory {
	@Override
	public Button getButton() {
		return new ButtonLinux();
	}

	@Override
	public CheckBox getCheckBox() {
		return new CheckBoxLinux();
	}
}

// A Windows Factory can produce a Windows button and a Windows checkbox.
class GUIFactoryWin implements GUIFactory {
	@Override
	public Button getButton() {
		return new ButtonWin();
	}

	@Override
	public CheckBox getCheckBox() {
		return new CheckBoxWin();
	}	
}

public class Test {
	public static void generateButtonCheckBox(GUIFactory guiFactory) {
		Button b1 = guiFactory.getButton();
		b1.setLabel("Hello!");
		b1.click();
		
		CheckBox ch1 = guiFactory.getCheckBox();
		ch1.setText("Select this if you prefer XYZ ");
		ch1.setStatus(true);
	
		System.out.println(ch1.getStatus());				
	}
	
	public static void main(String[] args) {
		GUIFactory factory = new GUIFactoryWin();
		generateButtonCheckBox(factory);

		System.out.println(" -------------- ------------ ----------  ");
		
		factory = new GUIFactoryLinux();
		generateButtonCheckBox(factory);
	}
}