Design Patterns - Abstract Factory design pattern

We will start with what Abstract Factory design pattern is and then showcase an example on how to define various Factories and abstraction layers.

1. What is Abstract Factory design pattern?

Abstract Factory design pattern comes under the category creational pattern. It is also called factory of factories. It provides a way to encapsulate a group of factories which have common behaviour or theme without specifying which underlying concrete objects are created. It is one level of abstraction higher than the Factory design pattern.

In Factory design Pattern, we get instance of one of several sub-classes whereas in Abstract Factory design pattern we get instance of one of several factories which then get instance of one of several sub-classes.

2. Implementation

Let's take an example of Import and Export. There are many ways to import and/ or export data. For brevity, We will focus only on file based data import/ export specifically based on Plain, PDF and Excel. We are going to create factories; ImportFactory and ExportFactory. We will also create one producer class ImportExportFactoryProducer which will produce the factory based on the type parameter and futher these factories will create concrete classes for various type of Import and Export strategies.

Abstract Factory design pattern example

2.1. AbstractFactory


/**
* This is factory of factory gives the instance for particular strategy
* @author Gaurav Rai Mazra
*
*/

public abstract class AbstractImportExportFactory {
public static final int TYPE_EXCEL = 1;
public static final int TYPE_PDF = 2;
public static final int TYPE_PLAIN = 3;


public abstract ImportStrategy getImportStrategy(int strategyType);
public abstract ExportStrategy getExportStrategy(int strategyType);
}

/**
* @author Gaurav Rai Mazra
*/

public abstract class ImportExportFactoryTypes {
public static final int TYPE_IMPORT = 1;
public static final int TYPE_EXPORT = 2;
}

2.2. Concrete classes for AbstractFactory

ImportFactory

/**
* Import factory
* @author Gaurav Rai Mazra
*/

public class ImportFactory extends AbstractImportExportFactory {

private static ImportFactory importFactory = null;
private ImportFactory() {}

public static ImportFactory getInstance(Lock lock) {
try {
lock.lock();
if (importFactory == null)
importFactory = new ImportFactory();
}
finally {
lock.unlock();
}

return importFactory;
}

@Override
public ImportStrategy getImportStrategy(int strategyType) {
ImportStrategy importStrategy = null;
switch (strategyType) {
case TYPE_EXCEL:
importStrategy = new ExcelImport();
break;

case TYPE_PDF:
importStrategy = new PdfImport();
break;

case TYPE_PLAIN:
importStrategy = new PlainTextImport();
break;

default:
throw new RuntimeException("Unknown strategy type: " + strategyType);
}
return importStrategy;
}

@Override
public ExportStrategy getExportStrategy(int strategyType) {
throw new RuntimeException("method not supported in import factory");
}
}
ExportFactory
/**
* Factory to get proper strategy object based on its type
* @author Gaurav Rai Mazra
*/

public class ExportFactory extends AbstractImportExportFactory {

private static ExportFactory exportFactory = null;

private ExportFactory() {}

public static ExportFactory getInstance(Lock lock) {
try {
lock.lock();
if (exportFactory == null)
exportFactory = new ExportFactory();
}
finally {
lock.unlock();
}
return exportFactory;
}

@Override
public ImportStrategy getImportStrategy(int strategyType) {
throw new RuntimeException("method not supported in export factory");
}

@Override
public ExportStrategy getExportStrategy(int strategyType) {
ExportStrategy strategy = null;
switch (strategyType) {
case TYPE_EXCEL:
strategy = new ExcelExport();
break;

case TYPE_PDF:
strategy = new PdfExport();
break;

case TYPE_PLAIN:
strategy = new PlainTextExport();
break;

default:
throw new RuntimeException("Strategy not supported: " + strategyType);
}
return strategy;
}
}

2.3. Producer class

/**
* This is Factory producer class
* @author Gaurav Rai Mazra
*
*/

public class ImportExportFactoryProducer {
private static ImportExportFactoryProducer factoryInstance = null;
private static final Lock lock = new ReentrantLock();

private ImportExportFactoryProducer() {}

public static ImportExportFactoryProducer getInstance() {
try {
lock.lock();
if (factoryInstance == null)
factoryInstance = new ImportExportFactoryProducer();
}
finally {
lock.unlock();
}

return factoryInstance;
}


public AbstractImportExportFactory getFactory(int factoryType) {
AbstractImportExportFactory factory = null;
switch (factoryType) {
case ImportExportFactoryTypes.TYPE_IMPORT:
factory = ImportFactory.getInstance(lock);
break;

case ImportExportFactoryTypes.TYPE_EXPORT:
factory = ExportFactory.getInstance(lock);
break;

default:
throw new RuntimeException("Factory not supported: " + factoryType);
}
return factory;
}
}

2.4. Main class for test

/**
* @author Gaurav Rai Mazra
*/

public class AbstractFactoryTest {

public static void main(String[] args) {
int factoryType = ImportExportFactoryTypes.TYPE_EXPORT;
int strategyType = AbstractImportExportFactory.TYPE_EXCEL;

AbstractImportExportFactory ioFactory = ImportExportFactoryProducer.getInstance().getFactory(factoryType);

switch (factoryType) {
case ImportExportFactoryTypes.TYPE_EXPORT :
ExportStrategy exportStrategy = ioFactory.getExportStrategy(strategyType);
exportStrategy.export();
break;

case ImportExportFactoryTypes.TYPE_IMPORT :
ImportStrategy importStrategy = ioFactory.getImportStrategy(strategyType);
importStrategy.importFile();
break;
default:
throw new RuntimeException("FactoryType not supported: " + factoryType);
}
}
}

2.5. Various Strategies for Import and Export

/**
* @author Gaurav Rai Mazra
*/

public interface ImportStrategy {
public void importFile();
}

public class ExcelImport implements ImportStrategy {

@Override
public void importFile() {
// Logic to import excel file goes here
}
}

public class PdfImport implements ImportStrategy {

@Override
public void importFile() {
//Logic to import pdf goes here
}

}

public class PlainTextImport implements ImportStrategy {
@Override
public void importFile() {
//Logic to import plain text file
}
}

public interface ExportStrategy {
public void export();
}

public class ExcelExport implements ExportStrategy {

@Override
public void export() {
// Excel export code goes here
}

}

public class PlainTextExport implements ExportStrategy {
@Override
public void export() {
// Plain text export goes here
}
}

public class PdfExport implements ExportStrategy {

@Override
public void export() {
//Pdf export Goes here
}
}


Tags: Design Patterns, Abstract Factory design pattern, Creational design pattern, Factory of factories design pattern, Java

← Back home