Factory Method Design Pattern in Ruby

1. Definition

The Factory Method Design Pattern defines an interface for creating objects but allows subclasses to alter the type of objects that will be created. Instead of calling a constructor directly, a factory method is used to produce instances of a class.

2. Problem Statement

Consider a situation where a class cannot anticipate the type of objects it needs to create, or when a class wants its subclasses to specify the objects it creates. A direct instantiation using constructors can become complex and not scalable.

3. Solution

The Factory Method pattern suggests providing a separate method for object creation and pushing this responsibility to subclasses, enabling them to redefine and adjust the type of created objects.

4. Real-World Use Cases

1. GUI libraries where each OS provides a different implementation of a button or window.

2. Payment gateway integration where each provider has a different process.

3. Frameworks that need to instantiate classes, but the exact classes might not be known until runtime.

5. Implementation Steps

1. Declare a factory method in a base class with its default implementation or make it abstract.

2. Create concrete subclasses that override this factory method to return an instance of their choice.

6. Implementation in Ruby

# Base class with a factory method
class Creator
  def factory_method
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
  def operation
    product = factory_method
    "Base operation with: #{product.operation}"
  end
end
# Concrete creators that override the factory method
class ConcreteCreatorA < Creator
  def factory_method
    ConcreteProductA.new
  end
end
class ConcreteCreatorB < Creator
  def factory_method
    ConcreteProductB.new
  end
end
# Product interface
class Product
  def operation
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end
# Concrete products
class ConcreteProductA < Product
  def operation
    'Result from ConcreteProductA'
  end
end
class ConcreteProductB < Product
  def operation
    'Result from ConcreteProductB'
  end
end
# Client code
creator1 = ConcreteCreatorA.new
puts creator1.operation
creator2 = ConcreteCreatorB.new
puts creator2.operation

Output:

Base operation with: Result from ConcreteProductA
Base operation with: Result from ConcreteProductB

Explanation:

1. The Creator class has a factory_method that serves as a placeholder for creating Product objects.

2. The ConcreteCreatorA and ConcreteCreatorB subclasses provide their implementation of the factory_method, determining what product to instantiate.

3. The client code interacts with the factory method through the operation method of the Creator class. It remains unaware of the concrete classes used, ensuring the decoupling of client code from class instantiation.

7. When to use?

Use the Factory Method pattern when:

1. A class can't anticipate the class of objects it must create.

2. Subclasses are responsible for implementing the factory method to produce objects.

3. You want to provide a library of products and expose the creation logic to clients, but keep the main code decoupled from these classes.


Comments