Deep Dive into Creational Patterns - The Factory Method Pattern.

Hey software designers! Today, we’re exploring the Factory Method pattern. This pattern provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. Let’s dive into its workings, benefits, and real-world applications with detailed examples.

What is the Factory Method Pattern?

The Factory Method pattern is a creational design pattern that defines an interface for creating an object but allows subclasses to alter the type of objects that will be created. The Factory Method pattern promotes loose coupling by eliminating the need to bind application-specific classes into the code, allowing the code to refer to the newly created objects through their common interface.

Real-World Scenario

Imagine you’re developing a document editor that supports different types of documents (Word, PDF, Excel). Each type of document requires a different way of opening, editing, and saving. Without a systematic approach, you might end up with tightly coupled code that is hard to maintain and extend.

The Problem

When an application needs to create instances of multiple derived classes, hardcoding the object creation logic can lead to a tightly coupled and inflexible codebase. This approach makes it difficult to introduce new types or change existing types without modifying the existing code.

Without Factory Method Pattern

class DocumentEditor
  def open_document(type)
    case type
    when 'Word'
      WordDocument.new.open
    when 'PDF'
      PDFDocument.new.open
    when 'Excel'
      ExcelDocument.new.open
    else
      raise 'Unknown document type'
    end
  end
end

class WordDocument
  def open
    puts 'Opening Word document...'
  end
end

class PDFDocument
  def open
    puts 'Opening PDF document...'
  end
end

class ExcelDocument
  def open
    puts 'Opening Excel document...'
  end
end

editor = DocumentEditor.new
editor.open_document('Word')
editor.open_document('PDF')

Drawbacks: The code is tightly coupled to specific implementations and hard to extend.

The Solution: Factory Method Pattern

Using the Factory Method pattern, we can delegate the responsibility of creating objects to subclasses, promoting flexibility and extensibility.

With Factory Method Pattern

Step 1: Define the Product Interface

class Document
  def open
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

Step 2: Create Concrete Products

class WordDocument < Document
  def open
    puts 'Opening Word document...'
  end
end

class PDFDocument < Document
  def open
    puts 'Opening PDF document...'
  end
end

class ExcelDocument < Document
  def open
    puts 'Opening Excel document...'
  end
end

Step 3: Define the Creator Interface

class DocumentCreator
  def create_document
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  def open_document
    document = create_document
    document.open
  end
end

Step 4: Implement Concrete Creators

class WordDocumentCreator < DocumentCreator
  def create_document
    WordDocument.new
  end
end

class PDFDocumentCreator < DocumentCreator
  def create_document
    PDFDocument.new
  end
end

class ExcelDocumentCreator < DocumentCreator
  def create_document
    ExcelDocument.new
  end
end

Step 5: Implement Client Code

word_creator = WordDocumentCreator.new
word_creator.open_document

pdf_creator = PDFDocumentCreator.new
pdf_creator.open_document

excel_creator = ExcelDocumentCreator.new
excel_creator.open_document

Benefits: Promotes loose coupling, making the code more flexible and easier to extend.

Real-World Benefits

Scenario: Adding New Document Types

Imagine you need to add a new type of document (e.g., TextDocument). Using the Factory Method pattern, you can easily introduce new document types without modifying the existing code.

Without Factory Method Pattern:

class DocumentEditor
  def open_document(type)
    case type
    when 'Word'
      WordDocument.new.open
    when 'PDF'
      PDFDocument.new.open
    when 'Excel'
      ExcelDocument.new.open
    when 'Text'
      TextDocument.new.open
    else
      raise 'Unknown document type'
    end
  end
end

class TextDocument
  def open
    puts 'Opening Text document...'
  end
end

Drawbacks: Tightly coupled code that is difficult to maintain and extend.

With Factory Method Pattern:

class TextDocument < Document
  def open
    puts 'Opening Text document...'
  end
end

class TextDocumentCreator < DocumentCreator
  def create_document
    TextDocument.new
  end
end

text_creator = TextDocumentCreator.new
text_creator.open_document

Benefits: Clean, maintainable code with high flexibility and extensibility.

Conclusion

The Factory Method pattern is a powerful tool for creating objects in a flexible and extensible manner. It promotes loose coupling and enhances the maintainability of your code. By using the Factory Method pattern, you can easily introduce new types and alter existing ones without modifying the existing code. Incorporate the Factory Method pattern into your design strategies to build more robust and adaptable software systems.

Stay tuned for more insights into software design principles and patterns.

Thôi Lo Code Đi Kẻo Sếp nạt!