The Factory Method pattern and the Abstract Factory pattern are creational design patterns that enable the creation of objects in different ways. These patterns provide a way to encapsulate the object creation process and make it easier to exchange implementations without affecting client code. These patterns can be combined with other creational patterns like Singleton, Prototype, or Builder to address specific architectural challenges.
#### Factory Method pattern with Singleton pattern
The Factory Method pattern can be combined with the Singleton pattern to ensure that only one instance of a factory object is created in the entire application. This can be useful in situations where multiple objects of a certain type need to be created but only one factory object is needed. In this pattern combination, the Singleton pattern is used to ensure that only one instance of the factory is created and the Factory Method pattern is used to create the objects. The following Java code example shows how this pattern combination can be implemented:
public class MySingletonFactory {
private static MySingletonFactory instance = null;
private MySingletonFactory() {}
public static MySingletonFactory getInstance() {
if (instance == null) {
instance = new MySingletonFactory();
}
return instance;
}
public MyObject createMyObject() {
return new MyObject();
}
}
#### Abstract Factory pattern with Singleton pattern
The Abstract Factory pattern can also be combined with the Singleton pattern to ensure that only one instance of an abstract factory object is created in the entire application. This can be useful in situations where multiple families of related objects need to be created but only one instance of each factory is needed. In this pattern combination, the Singleton pattern is used to ensure that only one instance of the abstract factory is created and the Abstract Factory pattern is used to create the families of objects. The following Java code example shows how this pattern combination can be implemented:
public abstract class AbstractMyFactory {
public abstract MyObject createMyObject();
}
public class MyFactory extends AbstractMyFactory {
private static MyFactory instance = null;
private MyFactory() {}
public static MyFactory getInstance() {
if (instance == null) {
instance = new MyFactory();
}
return instance;
}
public MyObject createMyObject() {
return new MyObject();
}
}
#### Abstract Factory pattern with Prototype pattern
The Abstract Factory pattern can be combined with the Prototype pattern to enable the creation of new objects by copying existing objects. This can be useful in situations where multiple families of related objects need to be created and each family has slightly different configurations. In this pattern combination, the Prototype pattern is used to create a prototype object and the Abstract Factory pattern is used to create the families of objects by copying the prototype object and making slight modifications. The following Java code example shows how this pattern combination can be implemented:
public abstract class AbstractMyFactory {
public abstract MyObject createMyObject();
}
public class MyObject implements Cloneable {
// implementation of MyObject
public MyObject clone() {
return super.clone();
}
}
public class MyFactory extends AbstractMyFactory {
private MyObject prototype = new MyObject();
public MyObject createMyObject() {
MyObject newObject = prototype.clone();
// make modifications to newObject if necessary
return newObject;
}
}
#### Builder pattern with Abstract Factory pattern and Prototype pattern
The Builder pattern can be combined with the Abstract Factory pattern and the Prototype pattern to enable the creation of complex objects with different configurations. This can be useful in situations where multiple families of related objects need to be created and each family has complex configurations. In this pattern combination, the Abstract Factory pattern is used to create the families of prototype objects, the Prototype pattern is used to create a prototype of each complex object, and the Builder pattern is used to build the final objects by copying the prototype and using the builder to modify the object’s configuration. The following Java code example shows how this pattern combination can be implemented:
public abstract class AbstractMyFactory {
public abstract MyObjectPrototype createMyObjectPrototype();
}
public interface MyObjectPrototype extends Cloneable {
MyObjectPrototype clone();
void setProperty1(Property1 property1);
void setProperty2(Property2 property2);
// other setter methods for properties
MyObject build();
}
public class MyObject implements Serializable {
// implementation of MyObject
}
public class MyObjectPrototypeImpl implements MyObjectPrototype {
private MyObject object = new MyObject();
private Property1 property1 = null;
private Property2 property2 = null;
// other properties
public void setProperty1(Property1 property1) {
this.property1 = property1;
}
public void setProperty2(Property2 property2) {
this.property2 = property2;
}
public MyObjectPrototype clone() {
MyObjectPrototypeImpl newPrototype = new MyObjectPrototypeImpl();
newPrototype.object = this.object.clone();
newPrototype.property1 = this.property1.clone();
newPrototype.property2 = this.property2.clone();
// other properties
return newPrototype;
}
public MyObject build() {
// set properties on object
object.setProperty1(property1);
object.setProperty2(property2);
// other properties
return object;
}
}
public class MyObjectBuilder {
private MyObjectPrototype prototype;
public MyObjectBuilder(AbstractMyFactory factory) {
prototype = factory.createMyObjectPrototype();
}
public void setProperty1(Property1 property1) {
prototype.setProperty1(property1);
}
public void setProperty2(Property2 property2) {
prototype.setProperty2(property2);
}
// other setter methods
public MyObject build() {
return prototype.build();
}
}
In conclusion, there are many ways to combine creational design patterns to address specific architectural challenges. The combination of patterns will depend on the requirements of the application and the design goals of the architecture.