Abstract
Factory Creational
Design Pattern
Previous page: Factory Pattern
Next page: Singleton Pattern
Name: Abstract Factory - Creational Design Pattern
Motivation:
Provide an interface for creating families of related or dependant objects without
specifying their concrete classes. For instance if one wishes to offer multiple
"looks" and "feels" to a product, but the product should not know which motif it
is using. This would then allow for the motif to be easily altered at run-time.
It should also be used "when a system should be independent of how its products
are created, composed, and represented." (p. 88) [4].
Furthermore it aids in grouping related families of products, as we will show in
the example below - and beyond grouping it can also enforce that these products
are only used in their intended groups. The pattern also supports the principle
of information hiding since the client is only offered / knows about the interface,
the client does not know anything about the actual data structure of a concrete
product, and additionally does not know which concrete product it is dealing with
at any given time..
Applicability: TBA
Participants:
The IPresentationFactory interface is implemented by the concrete factories. It defines the operations that they must implement when creating their "products".
In our case we are creating various looks and feels for the UI of mobile devices.
Thus the interface must define factory operations that are relevant to a UI.
The concrete factories are in our case LargeDeviceFactory and SmallScreenDeviceFactory.
They both implement the interface IPresentationFactory.
The abstract classes Box and Button are our two products, (naturally in a real-life
scenario one would have far more UI elements than just a Box and a Button). The
factories LargeDeviceFactory and SmallScreenDeviceFactory produce their separate
versions of these two products.
These versions of the products exist in the form of the classes SymbianBtn and SymbianMsg
(those are manufactured by the LargeDeviceFactory), whilst the products created
by SmallScreenDeviceFactory are called MiniBtn and MiniMsg.
The Client class is the consumer in our little example - actually this consumer
isn't a very fussy one at all, he doesn't really care to know what sort of products
he receives he just knows he wants a button class and a message class that he can
perform a set of pre-defined operations on. The client goes off to the factory and
receives a message (box) object and a button object, he doesnt know what sort they
are - he only knows the interfaces they implement and thus the operations they provide.
Sample Code:
public interface IPresentationFactory
{
public Button CreateButtons();
public Box CreateMessageBoxes();
}
public class LargeDeviceFactory implements IPresentationFactory
{
public Button CreateButtons()
{ return new SymbianBtn(); }
public Box CreateMessageBoxes()
{ return new SymbianMsg(); }
}
public class SmallScreenDeviceFactory implements IPresentationFactory
{
public Button CreateButtons()
{return new MiniBtn(); }
public Box CreateMessageBoxes()
{return new MiniMsg();}
}
public abstract class Box
{
public abstract void setButton(Button btn);
public void showBox() {;}
}
public abstract class Button
{
private String text = "";
public void SetText(String txt)
{text = txt;}
}
public class MiniBtn extends Button { }
public class MiniMsg extends Box
{
public void setButton(Button btn)
{
System.out.println(" a button of type " + btn.getClass().getSimpleName()
+ " was added to my MiniMsg");
}
}
public class SymbianBtn extends Button { }
public class SymbianMsg extends Box
{
public void setButton(Button btn)
{
System.out.println(" a button of type " + btn.getClass().getSimpleName()
+ " was added to my SymbianMsg");
}
}
public class Client
{
private Box box;
private Button button;
public Client(IPresentationFactory factory)
{
box = factory.CreateMessageBoxes();
button = factory.CreateButtons();
}
public void AddButtonToMessage()
{ box.setButton(button); }
}
Main()
{
Client client = new Client(new SmallScreenDeviceFactory());
client.AddButtonToMessage();
client = new Client(new LargeDeviceFactory());
client.AddButtonToMessage();
}
OUTPUT
a button of type MiniBtn was added to my MiniMsg
a button of type SymbianBtn was added to my SymbianMsg
Known uses and consequences:
The scenarios are outlined above in the first section "Motivation", the consequences
of using the pattern as outlined by the GoF (p.89) are on the positive side that
"it isolates concrete classes... Because a factory encapsulate the responsibility
and the process of creating product objects, it isolates clients from implementation
classes". They also point out that "it makes exchanging product families easy" -
this is due to the shared interface and the fact that a concrete factory is only
created once, making it easy to exchange. A third benefit is that "it promotes consistency
among products" - once again this is due to the shared interface of the AbstractFactory.
On a negative sidenote the use of this pattern also reduces the extendability of
the solution, since if one wishes to add a new product to the factory one would
have to alter both the interface IPresentationFactory and add a new abstract class
which would have to be created for all existing families.
Related Patterns:
There are other related patterns, such as factory and reflective
factory
that can be used instead. GoF indentify that the Singleton pattern could be used
in connection with this pattern, since on would in most cases only wish to create
one instance of each factory type.
|