Introduction
Abstract Factory design pattern comes under creational design 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 Factory 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.
Implementation
We are going to create Factories for Import and Export. We have one producer class ImportExportFactoryProducer
which produces the factory based on type i,e. if instance of ImportFactory
is required or ExportStrategy
is required which then initialize the concrete classes for ImportStrategy
or ExportStrategy
.
1. AbstractFactoryTest class
package com.gauravbytes.test; import com.gauravbytes._import.ImportStrategy;import com.gauravbytes.export.ExportStrategy;import com.gauravbytes.importexport.factory.AbstractImportExportFactory;import com.gauravbytes.importexport.factory.ImportExportFactoryProducer;import com.gauravbytes.importexport.factory.ImportExportFactoryTypes; /** * @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: break; } } }
2. FactoryProducer class, In our case ImportExportFactoryProducer
package com.gauravbytes.importexport.factory; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 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: break; } return factory; } }
3. Factory of Factory and the concrete factories . In our case AbstractImportExportFactory, ImportFactory and ExportFactory.
package com.gauravbytes.importexport.factory; import com.gauravbytes._import.ImportStrategy;import com.gauravbytes.export.ExportStrategy; /** * 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); }
package com.gauravbytes.importexport.factory; /** * @author Gaurav Rai Mazra */ public abstract class ImportExportFactoryTypes { public static final int TYPE_IMPORT = 1; public static final int TYPE_EXPORT = 2; }
package com.gauravbytes.importexport.factory; import com.gauravbytes._import.ExcelImport;import com.gauravbytes._import.ImportStrategy;import com.gauravbytes._import.PdfImport;import com.gauravbytes._import.PlainTextImport;import com.gauravbytes.export.ExportStrategy; import java.util.concurrent.locks.Lock; /** * 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: break; } return importStrategy; } @Override public ExportStrategy getExportStrategy(int strategyType) { return null; } }
package com.gauravbytes.importexport.factory; import com.gauravbytes._import.ImportStrategy;import com.gauravbytes.export.ExcelExport;import com.gauravbytes.export.ExportStrategy;import com.gauravbytes.export.PdfExport;import com.gauravbytes.export.PlainTextExport; import java.util.concurrent.locks.Lock; /** * 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) { return null; } @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: break; } return strategy; } }
4. ImportStrategy and their concrete classes
package com.gauravbytes._import; /** * @author Gaurav Rai Mazra */ public interface ImportStrategy { public void importFile(); }
package com.gauravbytes._import; /** * @author Gaurav Rai Mazra */ public class ExcelImport implements ImportStrategy { @Override public void importFile() { // Logic to import excel file goes here } }
package com.gauravbytes._import; /** * @author Gaurav Rai Mazra */ public class PdfImport implements ImportStrategy { @Override public void importFile() { //Logic to import pdf goes here } }
package com.gauravbytes._import; /** * @author Gaurav Rai Mazra */ public class PlainTextImport implements ImportStrategy { @Override public void importFile() { //Logic to import plain text file } }
5. ExportStrategy with their concrete classes
package com.gauravbytes.export; /** * @author Gaurav Rai Mazra */ public interface ExportStrategy { public void export(); }
package com.gauravbytes.export; /** * @author Gaurav Rai Mazra */ public class ExcelExport implements ExportStrategy { @Override public void export() { // Excel export code goes here } }
package com.gauravbytes.export; /** * @author Gaurav Rai Mazra */ public class PlainTextExport implements ExportStrategy { @Override public void export() { // Plain text export goes here } }
package com.gauravbytes.export; /** * @author Gaurav Rai Mazra */ public class PdfExport implements ExportStrategy { @Override public void export() { //Pdf export Goes here } }