Thursday, November 29, 2012

Creational Patterns: Abstract Factory

In this post I am going to show you implement the Abstract Factory pattern in Java. 

Description

The Abstract Factory pattern presents an interface for creating a family of products in a way that the client that uses those doesn't know anything about the concrete classes.


Solution offered by the pattern

This pattern is based on the definition of interfaces for every kind of product. There will be concrete classes that implement those interfaces that allow clients to make use of the products. The product families will be created by an object known as factory.
Every family has its particular factory used by the client to create products instances. Because the aim is not to tie the client to a specific factory, these factory implement a common interface known by the client.

Pattern structure


Abstract Factory Design Pattern Structure

Design pattern application - schema model


Abstract Factory Application - Widgets schema

Partecipants: 

  • AbstractFactory: interface WidgetFactory
- declares operations that create and return products.  
- the returned products are all AbstractProduct
  • ConcreteFactory: classes WindowsWidgetFactory, LinuxWidgetFactory, MacWidgetFactory. 
- implements the AbstractFactory. Creates and returns specific objects correnspondent to specific objects (ConcreteProduct).
  • AbstracProduct: interfaces Widget, TextBox, ComboBox, ListBox.
- define the operation that characterize the different generic types of products.
  • ConcreteProduct: classes WindowsTextBox, LinuxTextBox, MacTextBox, WindowsComboBox, LinuxComboBox, MacComboBox, WindowsListBox, LinuxListBox, MacListBox.
- define the products created by the ConcreteFactory. 
  • Client: class Client.
- uses the AbstractFactory to call the ConcreteFactory of a product family.   
- uses products by their interface AbstractProduct.

Code Description

Create the interfaces that the classes of every product family will implement. Widget is a marker interface used to identify interface components, while the interfaces TextBox, ComboBox and ListBox define the methods the clients invoke to draw the components. 


 
package com.fa.abstractfactory.product;

public interface Widget { }
 
package com.fa.abstractfactory.product;

public interface TextBox extends Widget {

	public void draw();
}
 
package com.fa.abstractfactory.product;

public interface ListBox extends Widget {

	public void draw();
}
 
package com.fa.abstractfactory.product;

public interface ComboBox extends Widget {

	public void draw();
}

We do implement the concrete classes of the products.


 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;

public class LinuxComboBox implements ComboBox{

	private List comboList;
	
	public LinuxComboBox(List list) {
		System.out.println("LinuxComboBox");
		this.comboList = list;
	}
	
	public void draw() {
		for(int i=0; i < comboList.size(); i++) {
			System.out.println("- " + comboList.get(i) + " -");
		}
	}

}

 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;

public class MacComboBox implements ComboBox {

	private List comboList;
	
	public MacComboBox(List list) {
		System.out.println("MacComboBox");
		this.comboList = list;
	}
	public void draw() {
		for(int i=0; i < comboList.size(); i++) {
			System.out.println("| " + comboList.get(i) + " |");
		}
	}
}


 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;

public class WindowsComboBox implements ComboBox {

	private List comboList;
	
	public WindowsComboBox(List list) {
		System.out.println("WindowsComboBox");
		this.comboList = list;
	}
	public void draw() {
		for(int i=0; i < comboList.size(); i++) {
			System.out.println("< " + comboList.get(i) + " >");
		}
	}

}


 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ListBox;

public class LinuxListBox implements ListBox{

	private List list;
	
	public LinuxListBox(List list) {
		System.out.println("LinuxListBox");
		this.list = list;
	}
	
	public void draw() {
		for(int i=0; i < list.size(); i++) {
			System.out.println("- " + list.get(i) + " -");
		}
	}

}

 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ListBox;

public class MacListBox implements ListBox{

	private List list;
	
	public MacListBox(List list) {
		System.out.println("MacListBox");
		this.list = list;
	}
	public void draw() {

		for(int i=0; i < list.size(); i++) {
			System.out.println("| " + list.get(i) + " |");
		}
	}

}

 
package com.fa.abstractfactory.product.impl;

import java.util.List;

import com.fa.abstractfactory.product.ListBox;

public class WindowsListBox implements ListBox {

	private List list;
	
	public WindowsListBox(List list) {
		System.out.println("WindowsListBox");
		this.list = list;
	}
	public void draw() {

		for(int i=0; i < list.size(); i++) {
			System.out.println("< " + list.get(i) + " >");
		}
	}
	
}

 
package com.fa.abstractfactory.product.impl;

import com.fa.abstractfactory.product.TextBox;

public class LinuxTextBox implements TextBox {

	private String text;
	
	public LinuxTextBox(String value) {
		System.out.println("LinuxTextBox");
		this.text = value;
	}
	
	public void draw() {
		System.out.println("- " + text + " -");
	}

}

 
package com.fa.abstractfactory.product.impl;

import com.fa.abstractfactory.product.TextBox;

public class MacTextBox implements TextBox{

	private String text;
	
	public MacTextBox(String value) {
		System.out.println("MacTextBox");
		this.text = value;
	}
	
	public void draw() {
		System.out.println("| " + text + " |");
	}

}

 
package com.fa.abstractfactory.product.impl;

import com.fa.abstractfactory.product.TextBox;

public class WindowsTextBox implements TextBox {

	private String text;
	
	public WindowsTextBox(String text) {
		System.out.println("WindowsTextBox");
		this.text = text;
	}
	
	public void draw() {
		System.out.println("< " + text + " >");
	}

}

The AbstractFactory interface defines the methods that return the generic type of Products.

 
package com.fa.abstractfactory.factory;

import java.util.List;

import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;

public interface WidgetFactory {
	TextBox createTextBox(String value);
	ListBox createListBox(List list);
	ComboBox createComboBox(List list);
}

Than we define the ConcreteFactory classes that create and return the concrete product for each family


 
package com.fa.abstractfactory.productfactory;

import java.util.List;

import com.fa.abstractfactory.factory.WidgetFactory;
import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;
import com.fa.abstractfactory.product.impl.LinuxComboBox;
import com.fa.abstractfactory.product.impl.LinuxListBox;
import com.fa.abstractfactory.product.impl.LinuxTextBox;

public class LinuxWidgetFactory implements WidgetFactory{

	@Override
	public TextBox createTextBox(String value) {
		return new LinuxTextBox(value);
	}

	@Override
	public ListBox createListBox(List list) {
		return new LinuxListBox(list);
	}

	@Override
	public ComboBox createComboBox(List list) {
		return new LinuxComboBox(list);
	}

}

 
package com.fa.abstractfactory.productfactory;

import java.util.List;

import com.fa.abstractfactory.factory.WidgetFactory;
import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;
import com.fa.abstractfactory.product.impl.MacComboBox;
import com.fa.abstractfactory.product.impl.MacListBox;
import com.fa.abstractfactory.product.impl.MacTextBox;

public class MacWidgetFactory implements WidgetFactory{

	@Override
	public TextBox createTextBox(String text) {
		return new MacTextBox(text);
	}

	@Override
	public ListBox createListBox(List list) {
		return new MacListBox(list);
	}

	@Override
	public ComboBox createComboBox(List list) {
		return new MacComboBox(list);
	}

}

 
package com.fa.abstractfactory.productfactory;

import java.util.List;

import com.fa.abstractfactory.factory.WidgetFactory;
import com.fa.abstractfactory.product.ComboBox;
import com.fa.abstractfactory.product.ListBox;
import com.fa.abstractfactory.product.TextBox;
import com.fa.abstractfactory.product.impl.WindowsComboBox;
import com.fa.abstractfactory.product.impl.WindowsListBox;
import com.fa.abstractfactory.product.impl.WindowsTextBox;

public class WindowsWidgetFactory implements WidgetFactory{

	@Override
	public TextBox createTextBox(String text) {
		return new WindowsTextBox(text);
	}

	@Override
	public ListBox createListBox(List list) {
		return new WindowsListBox(list);
	}

	@Override
	public ComboBox createComboBox(List list) {
		return new WindowsComboBox(list);
	}

}


The Client class defines the objects that every family product uses. Its constructor receives an object correnspondent to a particular family. The test method defines an instance for every particular family product and applies the different methods defined by the interface that the products implement. Note that the Client uses the Products without knowing which concrete object they belong to.
package com.fa.abstractfactory.client;

import java.util.Arrays;
import java.util.List;

import com.fa.abstractfactory.factory.*;
import com.fa.abstractfactory.product.impl.MacComboBox;
import com.fa.abstractfactory.product.impl.MacListBox;
import com.fa.abstractfactory.product.impl.MacTextBox;
import com.fa.abstractfactory.productfactory.MacWidgetFactory;

public class Client {

	private WidgetFactory factory;
	
	public Client(WidgetFactory factory) {
		this.factory = factory;
	}
	
	public void test() {
		
		factory.createTextBox("Text").draw();
		
		List list = Arrays.asList("First", "Second", "Third");
		factory.createListBox(list).draw();
		
		factory.createComboBox(list).draw();

	}
	
}


Next there is an example class that instantiates 3 Client objects passing to their constructor a family of product:
package com.fa.abstractfactory.test;

import com.fa.abstractfactory.client.Client;
import com.fa.abstractfactory.productfactory.LinuxWidgetFactory;
import com.fa.abstractfactory.productfactory.MacWidgetFactory;
import com.fa.abstractfactory.productfactory.WindowsWidgetFactory;

public class AbstractFactoryExample {
	
	public static void main(String[] args) {
		
		Client client1 = new Client(new MacWidgetFactory());
		client1.test();
		
		Client client2 = new Client(new LinuxWidgetFactory());
		client2.test();
		
		Client client3 = new Client(new WindowsWidgetFactory());
		client3.test();
	}
	
}


Next image shows you the console output, resulting from launching the previous starter class.
MacTextBox
| Text |
MacListBox
| First |
| Second |
| Third |
MacComboBox
| First |
| Second |
| Third |
LinuxTextBox
- Text -
LinuxListBox
- First -
- Second -
- Third -
LinuxComboBox
- First -
- Second -
- Third -
WindowsTextBox
< Text >
WindowsListBox
< First >
< Second >
< Third >
WindowsComboBox
< First >
< Second >
< Third >

No comments:

Post a Comment