Abstract Factory Pattern
[tr] Türkçe Oku 2023-06-11
Once upon a time, there was a kingdom, and the name of this kingdom was “Abstract Factory”. Although it seemed abstract, everything in this kingdom had a purpose, a certain order, and a specific design. There were certain rules on how everything was made, and these rules were based on design patterns that regulated the creation of objects.
In the kingdom of Abstract Factory, the King, known as AbstractFactory, would manage the factories of different types of products. The King thought that a factory should be able to produce various products at the same time. The King would give each of these factories the task of creating products from the same family. For example, one factory could create a Button and a TextField, while another could create a Slider and a Dropdown.
This concept is implemented in the C# language as follows:
public abstract class AbstractFactory
{
public abstract IButton CreateButton();
public abstract ITextField CreateTextField();
}
public class FactoryA : AbstractFactory
{
public override IButton CreateButton()
{
return new ButtonA();
}
public override ITextField CreateTextField()
{
return new TextFieldA();
}
}
public class FactoryB : AbstractFactory
{
public override IButton CreateButton()
{
return new ButtonB();
}
public override ITextField CreateTextField()
{
return new TextFieldB();
}
}
The same concept in Java:
public interface AbstractFactory {
Button createButton();
TextField createTextField();
}
public class FactoryA implements AbstractFactory {
public Button createButton() {
return new ButtonA();
}
public TextField createTextField() {
return new TextFieldA();
}
}
public class FactoryB implements AbstractFactory {
public Button createButton() {
return new ButtonB();
}
public TextField createTextField() {
return new TextFieldB();
}
}
Let’s see this example in Python:
from abc import ABC, abstractmethod
class AbstractFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_text_field(self):
pass
class FactoryA(AbstractFactory):
def create_button(self):
return ButtonA()
def create_text_field(self):
return TextFieldA()
class FactoryB(AbstractFactory):
def create_button(self):
return ButtonB()
def create_text_field(self):
return TextFieldB()
We can also apply this example in Go:
type AbstractFactory interface {
CreateButton() Button
CreateTextField() TextField
}
type FactoryA struct{}
func (f FactoryA) CreateButton() Button {
return ButtonA{}
}
func (f FactoryA) CreateTextField() TextField {
return TextFieldA{}
}
type FactoryB struct{}
func (f FactoryB) CreateButton() Button {
return ButtonB{}
}
func (f FactoryB) CreateTextField() TextField {
return TextFieldB{}
}
The situation in Rust is as follows:
pub trait AbstractFactory {
fn create_button(&self) -> Box<dyn Button>;
fn create_text_field(&self) -> Box<dyn TextField>;
}
pub struct FactoryA;
pub struct FactoryB;
impl AbstractFactory for FactoryA {
fn create_button(&self) -> Box<dyn Button> {
Box::new(ButtonA)
}
fn create_text_field(&self) -> Box<dyn TextField> {
Box::new(TextFieldA)
}
}
impl AbstractFactory for FactoryB {
fn create_button(&self) -> Box<dyn Button> {
Box::new(ButtonB)
}
fn create_text_field(&self) -> Box<dyn TextField> {
Box::new(TextFieldB)
}
}
That is the story of the Abstract Factory kingdom. We understood how different varieties of products could be produced by a single factory. Each factory creates a certain product family, providing us with consistency among products. This is very useful especially when there is a specific relationship between the products or when a specific factory needs to create only certain types of products. This way, one factory can only create one type of button, while another factory can create a different type of button.
This story shows what the abstract factory design pattern is and how it can be used. In each language, there are specific ways to apply this pattern, but the basic concept is always the same: a factory creates a series of products belonging to a certain family, and there is a specific relationship between these products. This makes the code more orderly and understandable, and most importantly, it makes the code easier to maintain and extend.