Abstract Factory

Using references to interfaces instead of references to concrete classes is an important way of minimizing ripple effects. The user of an interface reference is always protected from changes to the underlying implementation.

The Abstract Factory pattern is one example of this technique. Users of an Abstract Factory can create families of related objects without any knowledge of their concrete classes. A typical business application would usually not need to use this technique, at least as applied to Data Access Objects.

You may find that a Plugin Factory is a better alternative, with less complexity than an Abstract Factory.

Example

An Abstract Factory is a major part of the full Data Access Object (DAO) scheme. Here, the idea is to allow the business layer to interact with the data layer almost entirely through interface references. The business layer remains ignorant of the concrete classes which implement the datastore.

There are two distinct families of items here:

Let's take the example of storing Device objects. They may be stored in either a text file or a relational database. Since the calling code needs to remain ignorant of which is being used, it's natural, of course, to define an interface that reflects this, along with two corresponding concrete implementations:
public interface DeviceDAO {

  Device fetch(String id) throws DataAccessException;
  
  void add(Device device) throws DataAccessException;
  
  void change(Device device) throws DataAccessException;
  
  void delete(Device device) throws DataAccessException;
} 
...with an implementation for a file system:
final class DeviceDAOFileSys implements DeviceDAO {
  
  /*
   * The constructor will usually be passed any required config data.
   */
  
  @Override public void add(Device device) throws DataAccessException {
    //elided...
  }
  
  @Override public void change(Device device) throws DataAccessException {
    //elided...
  }
  
  @Override public void delete(Device device) throws DataAccessException {
    //elided...
  }
  
  @Override public Device fetch(String id) throws DataAccessException {
    //elided...
    return null;
  }

} 
...and an implementation for a relational database:
final class DeviceDAORelational implements DeviceDAO {
  
  /*
   * The constructor will usually be passed any required config data.
   */
  
  @Override public void add(Device device) throws DataAccessException {
    //elided...
  }
  
  @Override public void change(Device device) throws DataAccessException {
    //elided...
  }
  
  @Override public void delete(Device device) throws DataAccessException {
    //elided...
  }
  
  @Override public Device fetch(String id) throws DataAccessException {
    //elided...
    return null;
  }
  
} 
(The details of these classes are left out, so that you can see the structure better.)

Next, the calling application needs a way to interact with the database, without knowing about the concrete implementations. This is done using a factory class:

/**
 Returns all DAO instances.
  
 Reads a configuration item (defined by your program) to decide 
 which family of DAO objects it should be returning, for the currently 
 running program, either file-based or relational-based.
  
 The configuration mechanism may be a System property, a properties file, an
 XML file, and so on. The config is often read when the system initializes,
 perhaps using a static initializer.
*/
final class DAOFactory {
  
  /* some would implement all of the methods here as static methods */
  
  DeviceDAO getDeviceDAO(){
    //elided:
    return null;
  }

  UserDAO getUserDAO(){
    //elided:
    return null;
  }
  
} 

public final class Application {
  
  /**
   This calling code is completely unaware of the underlying datastore.
   It could be a text file, or a relational database.
  */
  void addNewDevice(Device device){
    DAOFactory factory = new DAOFactory();
    try {
      factory.getDeviceDAO().add(device);
    }
    catch (DataAccessException ex) {
      ex.printStackTrace();
    }
  }

}
 

See Also :
Factory methods
Data access objects
Data exception wrapping
Construct Object using class name
Minimize ripple effects
Parse parameters into domain objects
Plugin Factory