We will start with what Abstract Factory design pattern is and then showcase an example on how to define various Factories
and abstraction layers.
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.
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.
/**
* 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;
}
/**
* 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");
}
}
/**
* 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;
}
}
/**
* 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;
}
}
/**
* @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);
}
}
}
/**
* @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
}
}