12/08/2018, 13:13

Design Pattern - Factory Method

Để hiểu hơn về factory, hãy cùng bắt đầu với một vấn đề trong lập trình. Hãy tưởng tượng bạn được yêu cầu build một mô hình cuộc sống trong một cái ao, với những chú vịt. Bạn sẽ làm thế nào ? Đầu tiên hãy xây dựng class cho chú vịt Duck class Duck def initialize ( name ) @name ...

Để hiểu hơn về factory, hãy cùng bắt đầu với một vấn đề trong lập trình. Hãy tưởng tượng bạn được yêu cầu build một mô hình cuộc sống trong một cái ao, với những chú vịt. Bạn sẽ làm thế nào ?

Đầu tiên hãy xây dựng class cho chú vịt Duck

class Duck
  def initialize(name)
    @name = name
  end
  def eat
    puts("Duck #{@name} is eating.")
  end
  def speak
    puts("Duck #{@name} says Quack!")
  end
  def sleep
    puts("Duck #{@name} sleeps quietly.")
  end
end

Tiếp theo là cái ao Pond với nhiều vịt Duck:

class Pond
  def initialize(number_ducks)
    @ducks = []
    number_ducks.times do |i|
     duck = Duck.new("Duck#{i}")
     @ducks << duck
    end
  end
  def simulate_one_day
    @ducks.each {|duck| duck.speak}
    @ducks.each {|duck| duck.eat}
    @ducks.each {|duck| duck.sleep}
  end
end

Nếu giờ chúng ta có thêm yêu cầu xây dựng thêm object con ếch Frog ở vũng nước Puddle thì phải làm sao ? Sẽ rất dễ để tạo 1 class Frog vì nó khá giống với interface của con vịt Duck.

class Frog
  def initialize(name)
    @name = name
  end
  def eat
    puts("Frog #{@name} is eating.")
  end
  def speak
    puts("Frog #{@name} says Crooooaaaak!")
  end
  def sleep
    puts("Frog #{@name} doesn't sleep; he croaks all night!")
  end
end

Nhưng với class Pond thì hiện chúng ta đang implement chỉ khởi tạo cho Duck. Nếu muốn thêm Frog thì cần tách riêng các sinh vật sống trong ao, cụ thể là Duck hoặc Frog. Nếu bạn bằng cách nào đó có thể khiến class Pond hỗ trợ cả Duck và Frog thì cũng rất khó nếu muốn gọi ra các method của từng object vì chúng ta không thể biết chúng ta đang gọi object thuộc class nào.

Có một cách để giải quyết vấn đề chọn class phù hợp đó là tách thành các subclass thông qua một base class.

class Pond
  def initialize(number_animals)
    @animals = []
    number_animals.times do |i|
      animal = new_animal("Animal#{i}")
      @animals << animal
    end
  end
  def simulate_one_day
    @animals.each {|animal| animal.speak}
    @animals.each {|animal| animal.eat}
    @animals.each {|animal| animal.sleep}
  end
end

Chúng ta cần build 2 subclass của Pond, một cho Duck và một cho loại khác (Frog).

class DuckPond < Pond
  def new_animal(name)
    Duck.new(name)
  end
end
class FrogPond < Pond
  def new_animal(name)
    Frog.new(name)
  end
end

GoF gọi kỹ thuật giải quyết việc chọn class bằng cách chia thành các subclass là Factory Method pattern.

UML diagram của pattern này như sau:

uml factory method pattern.png

Trong ví dụ phía trên thì:

  • Creator chính là Pond class
  • Hai loại pond (DuckPond, FrogPond) chính là ConcreteCreator
  • Và 2 products là Duck class và Frog class.

Kết luận

Factory Method pattern là một trong những design pattern được sử dụng phổ biến, nó cung cấp một trong những cách tốt nhất để tạo ra một object.

Trong Factory Method pattern, chúng ta tạo ra object mà không lộ logic với client mà tham chiếu tới một đối tượng mới sử dụng một common interface.

Tham khảo

Github (updating):https://github.com/ducnhat1989/design-patterns-in-ruby

Sách: “DESIGN PATTERNS IN RUBY” của tác giả Russ Olsen

:

  • CÁC NGUYÊN TẮC TRONG DESIGN PATTERN
0