Abstract Factory design pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interfaces to create the concrete objects that are part of the theme.

Following example of Bank will illustrate the working of abstract factory pattern.

Go to the bank to make a deposit to your account,
  • You don’t walk up to a vault,
  • Pull out a drawer with your name on it,
  • Drop in your money,
  • Shut the drawer and leave.
Think about how you originally established, or opened, the account.
  • You probably went to the bank,
  • Spoke with an Account Manager and signed some papers.
  • In return, they gave you some checks, a passbook, or a bank card so you could access your account in the future.
The Account Manager is an example of a factory.
  • The person or Automated Teller Machine (ATM) that acts as account manager controls the creation of and/or access to individual accounts.

Applicability

  • A system should be independent of how its products are created, composed and represented
  • A system should be configured with one of multiple families of products
  • A family of related product objects is designed to be used together, and you need to enforce this constraint
  • You want to provide a class library of products, and you want to reveal just their interfaces, not their implementation

Example – Write a Cross Platform Window Toolkit

Write a toolkit to allow applications with GUI interfaces to run on multiple platforms (Mac, PC, OS/2, Unix motif ) using the look and feel of each platform

We will look at widgets: Windows, Menu’s and Buttons

Create an interface( or abstract class) for each widget and a concrete class for each platform

This allows the application to write to the widget interface

public void installDisneyMenu() {
   Menu disney = create a menu somehow
   disney.addItem( "Disney World" );
   disney.addItem( "Donald Duck" );
   disney.addItem( "Mickey Mouse" );
   disney.addGrayBar( );
   disney.addItem( "Minnie Mouse" );
   disney.addItem( "Pluto" ); etc.
}

How to create the widget? Use Factory

abstract class WidgetFactory {
   public Window createWindow();
   public Menu createMenu();
   public Button createButton();
}
class MacWidgetFactory extends WidgetFactory {
   public Window createWindow() {
      code to create a mac window
   }
   public Menu createMenu() {
      code to create a mac Menu
   }
   public Button createButton() {
      code to create a mac button
   }
}
class Win95WidgetFactory extends WidgetFactory {
public Window createWindow() {
code to create a Win95 window
}

public Menu createMenu() {
code to create a Win95 Menu
}

public Button createButton() {
code to create a Win95 button
}
}
Now to get code that works for all platforms we get:
public void installDisneyMenu(WidgetFactory myFactory) {
   Menu disney = myFactory.createMenu();
   disney.addItem( "Disney World" );
   disney.addItem( "Donald Duck" );
   disney.addItem( "Mickey Mouse" );
   disney.addGrayBar( );
   disney.addItem( "Minnie Mouse" );
   disney.addItem( "Pluto" );
   ...
}

We just need to make sure that the application for each platform creates the proper factory.

How Do Factories create Widgets?

Method 1- My Factory Method 

abstract class WidgetFactory {
   public Window createWindow();
   public Menu createMenu();
   public Button createButton();
}
class MacWidgetFactory extends WidgetFactory {
   public Window createWindow() {
      return new MacWidow()
   }
   public Menu createMenu() {
      return new MacMenu()
   }
   public Button createButton() {
      return new MacButton()
   }
}

Method 2- Their Factory Method 

abstract class WidgetFactory {
   private Window windowFactory;
   private Menu menuFactory;
   private Button buttonFactory;
   public Window createWindow() {
      return windowFactory.createWindow()
   }
   public Menu createMenu(); {
      return menuFactory.createWindow()
   }
   public Button createButton() {
      return buttonFactory.createWindow()
   }
}
class MacWidgetFactory extends WidgetFactory {
   public MacWidgetFactory() {
      windowFactory = new MacWindow();
      menuFactory = new MacMenu();
      buttonFactory = new MacButton();
   }
}
class MacWindow extends Window {
   public Window createWindow() {
      //blah
   }

abstract class WidgetFactory {
   private Window windowFactory;
   private Menu menuFactory;
   private Button buttonFactory;
   public Window createWindow() {
      return windowFactory.createWindow()
   }
   public Window createWindow( Rectangle size) {
      return windowFactory.createWindow( size )
   }
   public Window createWindow( Rectangle size, String title) {
      return windowFactory.createWindow( size, title)
   }
   public Window createFancyWindow() {
      return windowFactory.createFancyWindow()
   }
   public Window createPlainWindow() {
      return windowFactory.createPlainWindow()
   }
Using factory method allows abstract class to do all the different ways to create a window. Subclasses just provide the objects windowFactory, menuFactory, buttonFactory, etc.

Method 3- Prototype 

class WidgetFactory {
   private Window windowPrototype;
   private Menu menuPrototype;
   private Button buttonPrototype;
   public WidgetFactory( Window windowPrototype, Menu menuPrototype,
                                       Button buttonPrototype) {
      this.windowPrototype = windowPrototype;
      this.menuPrototype = menuPrototype;
      this.buttonPrototype = buttonPrototype;
   }
   public Window createWindow() {
      return windowFactory.createWindow()
   }
public Window createWindow( Rectangle size) {
      return windowFactory.createWindow( size )
   }
   public Window createWindow( Rectangle size, String title) {
      return windowFactory.createWindow( size, title)
   }
   public Window createFancyWindow() {
      return windowFactory.createFancyWindow()
   }

There is no need for subclasses of WidgetFactory.

Abstract Factory Implementation using Java

In this example we’ll apply the Factory Pattern to RMI. A factory implementation is useful when you need one object to control the creation of and/or access to other objects. By using a factory in RMI, you can reduce the number of objects that you need to register with the RMI registry.

Just like any other RMI program, there are a few basic players

A server

  • produces one or more remote objects,
  • each of which implements a remote interface

A client

  • accesses a name server (the rmiregistry )
  • to get a reference to one of the remote objects
The RMI registry
  • which facilitates the client’s initial contact with the server

There are two remote interfaces that the client understands,

Factory and Product

The FactoryImpl implements the Factory interface. The ProductImpl implements the Product interface

In previous example we saw how an Abstract Factory can be used to create widgets for a GUI environment. By designing the client to use the Abstract Factory interface, different factories can be created to generate different sets of widgets without requiring changes to the clients.

WidgetFactory.java

public interface WidgetFactory extends java.rmi.Remote {
   public ScrollBar createScrollBar() throws java.rmi.RemoteException;
public Window createWindow() throws java.rmi.RemoteException;
}

This class represents the RMI server interface for creating GUI widgets. The actual RMI server that implements this interface determines which type of Widget objects are returned to the clients.

ScrollBar.java 
This interface represents an abstract ScrollBar that would be returned from a WidgetFactory server.

public interface ScrollBar extends java.io.Serializable{
   public String toString();
}

Window.java 
This interface represents another GUI component that can be returned from a WidgetFactory.

public interface Window extends java.io.Serializable {
   public String toString();
}

Client.java 
This class is a simple client of the WidgetFactory that will grab a Window and ScrollBar and display the actual type of object that was loaded.

import java.rmi.*;

public class Client {public static void main(String[] args)
{
try {
    WidgetFactory factory = (WidgetFactory) Naming.lookup("rmi://"+ args[0]+ "/WidgetFactory");
    System.out.println("Window: "+factory.createWindow());
    System.out.println("ScrollBar: "+factory.createScrollBar());
} catch(Exception e){
       System.err.println("Failure creating widgets: " + e.getMessage());
}
}
}

MotifWidgetFactory.java 
This class is an implementation of the WidgetFactory that will return MotifWidgets.

import java.rmi.*;import java.rmi.server.*;
public class MotifWidgetFactory extends UnicastRemoteObject implements WidgetFactory {
public MotifWidgetFactory() throws RemoteException {
super();
try {
Naming.rebind("rmi:///WidgetFactory",this);
System.out.println("Server ready");
} catch (Exception e){
System.err.println("Failure setting up WidgetFactory: "+ e.getMessage());
}
}
        public static void main(String[] args){
try {
new MotifWidgetFactory();
} catch(Exception e){
System.err.println("Failure creating WidgetFactory:" + e.getMessage());
}
}
//Remote methods
public Window createWindow(){
return new MotifWindow();
}
public ScrollBar createScrollBar(){
return new MotifScrollBar();
}
}

MotifScrollBar.java 
This class is a Motif representation of a ScrollBar that will be returned by the MotifWidgetFactory.

public class MotifScrollBar implements ScrollBar {
public String toString(){
return "MotifScrollBar";
}
}

MotifWindow.java
This class is a Motif representation of a Window that will be returned by the MotifWidgetFactory.

public class MotifWindow implements Window {
public String toString(){
return "MotifWindow";
}
}

AWTWidgetFactory.java
This is a second implementation of a WidgetFactory that returns AWT widgets.

import java.rmi.*;
import java.rmi.server.*;

public class AWTWidgetFactory extends UnicastRemoteObject
implements WidgetFactory {
public AWTWidgetFactory() throws RemoteException{
super();
try {
Naming.rebind("rmi:///WidgetFactory",this);
System.out.println("Server ready");
} catch(Exception e){
System.err.println("Failure setting up WidgetFactory: "
+ e.getMessage());
}
}
public static void main(String[] args){
try {
new AWTWidgetFactory();
} catch(Exception e){
System.err.println("Failure creating WidgetFactory: "
+ e.getMessage());
}
}

//Remote methods
public Window createWindow(){
return new AWTWindow();
}

public ScrollBar createScrollBar(){
return new AWTScrollBar();
}
}

AWTScrollBar.java

public class AWTScrollBar implements ScrollBar {
public String toString(){
return "AWTScrollBar";
}
}

AWTWindow.java

public class AWTWindow implements Window {
public String toString(){
return "AWTWindow";
}
}

Consequences

  • It isolates concrete classes
  • It makes exchanging product families easy
  • It promotes consistency among products
  • Supporting new kinds of products is difficult
Tagged with: Design PatternJAVAObject Oriented
 

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

Looking for something?

Use the form below to search the site:


Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Related News Feeds

Set your Twitter account name in your settings to use the TwitterBar Section.