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 >

Sunday, November 25, 2012

Design Patterns

Creational Patterns

Creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to de design. Creational design patterns solve this problem somehow controlling this object creation.

Creational design patterns are further categorized into Object-creational patterns and Class-creational patterns, where Object-creational patterns deal with Object creation and Class-creational patterns deal with Class-instantiation. In greater details, Object-creational patterns defer part of its object creation to another object, while Class-creational patterns defer its objection creation to subclasses.

Five well-known design patterns that are part of creational patterns are:

  • Abstract Factory
  • Builder
  • Factory
  • Prototype
  • Singleton

Structural Patterns

Structural design patterns are those that ease the design by identifying a simple way to realize relationship between entities. Structural class-creation patterns use inheritance to compose interfaces. Structural object-patterns define ways to compose objects to obtain new functionality.

Example of structural patterns include:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Extensibility
  • Facade
  • Proxy

Behavioral Patterns

Behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. These patterns increase flexibility in carrying out this communication.

Examples of this type of design patterns include:

  • Chain of Responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template
  • Visitor

In my next posts I am going to show you how to implement some of the patterns listed above.