+15

Decorator Pattern in Ruby

I. Problem

Chúng ta cần thay đổi trách nhiệm của một đối tượng, thêm một số tính năng. Giải pháp tôi muốn giới thiệu là Decorator.Decorator pattern là một mẫu thiết kế cho phép chúng ta thêm hành vi vào đối tượng mà không ảnh hưởng đến các đối tượng khác của cùng một lớp. Decorator Pattern là một lựa chọn hữu ích để tạo các lớp con.

II. Solution

Trong Decorator pattern chúng ta tạo ra một đối tượng mà bao bọc một đối tượng khác để thực hiện hành động trên cùng một giao diện, giống như cấc phương thức chuyển tiếp. Tuy nhiên, trước khi ủy quyền cho đối tượng thực, nó thực hiện tính năng bổ sung trước. Vì tất cả các Decorator đều triển khai cùng một inteface cốt lõi, chúng ta có thể xây dựng các chuỗi các decorator và tập hợp chúng lại để kết hợp các tính năng khi runtime.

III. Example

Dưới đây là việc thực hiện của một đối tượng mà chỉ cần viết một dòng text vào một file:

class SimpleWriter
  def initialize(path)
    @file = File.open(path, 'w')
  end

  def write_line(line)
    @file.print(line)
    @file.print("\n")
  end

  def pos
    @file.pos
  end

  def rewind
    @file.rewind
  end

  def close
    @file.close
  end
end

Một lúc nào đó, chúng ta có thể cần in số dòng trước mỗi dòng hoặc thời gian hoặc tổng số ký tự.Chúng ta có thể đạt được điều này bằng cách thêm các phương thức mới vào Class thực hiện chính xác những gì chúng ta muốn, hoặc bằng cách tạo một subclass mới cho mỗi trường hợp sử dụng.Tuy nhiên, không có giải pháp nào trong số này là tối ưu.Trong trường hợp thứ nhất, khách hàng nên biết loại line nào sẽ được print ra mọi lúc.Với trường hợp sau, chúng ta có thể cần có một số lượng lớn các lớp con, đặc biệt nếu chúng ta muốn kết hợp các tính năng mới thì việc quản lý các class sẽ trở nên phức tạp.Vì vậy, hãy tạo một lớp Decorator dựa trên cơ sở thực hiện cùng một interface mà class Writer của chúng ta và các delegate trên nó:

class WriterDecorator
  def initialize(real_writer)
    @real_writer = real_writer
  end

  def write_line(line)
    @real_writer.write_line(line)
  end

  def pos
    @real_writer.pos
  end

  def rewind
    @real_writer.rewind
  end

  def close
    @real_writer.close
  end
end

Bây giờ, bằng cách extending class WriteDecorator, chúng ta có thể thêm các tính năng bổ sung ở trên cùng của basic writer, chẳng hạn như thêm đánh số dòng:

class NumberingWriter < WriterDecorator
  def initialize(real_writer)
    super(real_writer)
    @line_number = 1
  end

  def write_line(line)
    @real_writer.write_line("#{@line_number}: #{line}")
    @line_number += 1
  end
end

writer = NumberingWriter.new(SimpleWriter.new('final.txt'))
writer.write_line('Hello out there')

Nếu chúng ta tạo ra các decorator mà thực hiện cùng một interface cốt lõi, chúng ta có thể xâu chuỗi chúng lại:

class TimeStampingWriter < WriterDecorator
  def write_line(line)
    @real_writer.write_line("#{Time.new}: #{line}")
  end
end

writer = CheckSummingWriter.new(TimeStampingWriter.new(
            NumberingWriter.new(SimpleWriter.new('final.txt'))))
writer.write_line('Hello out there')

IV. Tham khảo


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí