12/08/2018, 17:30

Builder design pattern in Ruby

Theo GoF và cuốn sách tuyệt vời của họ "Design Patterns: Elements of Reusable Object-Oriented Software", builder pattern: " Tách riêng việc xây dựng một vật thể phức tạp từ biểu tượng của nó sao cho cùng một quá trình xây dựng có thể tạo ra các đại diện khác nhau." và nó là một phần của một mẫu ...

Theo GoF và cuốn sách tuyệt vời của họ "Design Patterns: Elements of Reusable Object-Oriented Software", builder pattern:

"Tách riêng việc xây dựng một vật thể phức tạp từ biểu tượng của nó sao cho cùng một quá trình xây dựng có thể tạo ra các đại diện khác nhau." và nó là một phần của một mẫu thiết kế đối tượng sáng tạo.

Builder pattern rất hữu ích khi xây dựng một đối tượng gì đó độc lập với các bộ phận tạo thành nó (các methods xây dựng đối tượng). Điều đó cũng định nghĩa một ứng dụng khác của builder pattern: hữu ích khi có nhiều cách để xây dựng các đối tượng phức tạp.

Hãy bắt đầu với một số ví dụ và xem chúng ta có thể cải tiến / refactor nó bằng cách sử dụng patter builder.

Giả sử chúng ta có cách tạo ra users:

class User
  attr_accessor :first_name, :last_name, :birthday, :gender, :roles, :status, :email, :password

  def initialize(first_name=nil, last_name=nil, birthday=nil, gender=nil, roles=[], status=nil, email=nil, password=nil)
    @first_name = first_name
    @last_name = last_name
    @birthday = birthday
    @gender = gender
    @roles = roles
    @status = status
    @email = email
    @password = password
  end
end

User.new('John', 'Doe', Time.new('1999-03-02'), 'm', ['admin'], 'active', 'test@test.com', 'abcdef')

Có vài vấn đề với cách tiếp cận đó:

  • Nó không có vẻ chuyên nghiệp
  • Chúng ta có danh sách rất dài của params với cách chúng ta có thể nhanh chóng một người dùng mới. Để làm điều này, bạn có thể gửi nil cho params nhất định, nhưng nó có thể trông rất lộn xộn,
  • Thêm params mới sẽ chỉ làm cho tình hình tồi tệ hơn,
  • Logic cách đối tượng được xây dựng được ẩn trong sự khởi tạo của nó.

Để trích xuất logic user được xây dựng như thế nào, chúng ta có thể sử dụng builder pattern ở đây.

Class user của chúng ta trở nên đơn giản:

class User
  attr_accessor :first_name, :last_name, :birthday, :gender, :roles, :status, :email, :password
end

và chúng ta muốn tạo nhanh chóng user mới bằng cách làm điều này:

UserBuilder.build do |builder|
  builder.set_name('John', 'Doe')
  builder.set_birthday('1999-03-02')
  builder.set_as_on_hold
  builder.set_as_men
  builder.set_as_admin
  builder.set_login_credentials('test@test.com', 'abcdef')
end

Chúng ta đang nói với buidler (UserBuilder) làm thế nào để xây dựng user mới bằng cách cung cấp cho nó kế hoạch chính xác (đại diện bởi khối trong ví dụ đó).

Hai lợi ích rõ ràng ở đây: không có danh sách dài các tham số và thuật toán người dùng đang xây dựng là gì ngoài lớp User.

Hãy thực hiện lớp UserBuilder.

class UserBuilder
  def self.build
    builder = new
    yield(builder)
    builder.user
  end

  def initialize
    @user = User.new
  end

  def set_name(first_name, last_name)
    @user.first_name = first_name
    @user.last_name = last_name
  end

  def set_birthday(birthday)
    @user.birthday = Time.new(birthday)
  end

  def set_as_active
    @user.status = 'active'
  end

  def set_as_on_hold
    @user.status = 'on_hold'
  end

  def set_as_men
    @user.gender = 'm'
  end

  def set_as_women
    @user.gender = 'f'
  end

  def set_as_admin
    @user.roles = ['admin']
  end

  def set_login_credentials(email, password)
    @user.email = email
    @user.password = password
  end

  def user
    @user
  end
end

UserBuilder có kiến thức làm thế nào để xây dựng các bộ phận của người sử dụng. Nó cho chúng ta một số cách dễ tiêu hóa nhất của việc xây dựng các đối tượng mới (set_name, set_as_active, ...) hơn là chỉ là sự khởi tạo của User từ ví dụ đầu tiên (chúng ta không cần phải biết về một số chi tiết ở mức độ thấp của những phần nào đó xây dựng một đối tượng người dùng).

Bạn có thể có các kế hoạch khác nhau như thế nào để tạo một người dùng mới (các khối được truyền vào phương thức UserBuilder.build) và bạn có thể luôn chắc chắn rằng người xây dựng của bạn (UserBuilder) sẽ biết cách sử dụng kế hoạch của bạn để xây dựng đối tượng mới.

Tham khảo: https://medium.com/kkempin/builder-design-pattern-in-ruby-dfa2d557ff1b

0