12/08/2018, 15:27

Private classes in Ruby

Tại sao private? Một trong những cách phổ biến nhất để làm cho một số đoạn code của bạn dễ hiểu hơn và rõ ràng hơn là trích xuất một lớp. Tuy nhiên, nhiều lần lớp này không dành cho việc sử dụng một cách public. Đó là một chi tiết thực hiện của một lớp lớn hơn. Nó không nên được sử dụng được bất ...

Tại sao private?

Một trong những cách phổ biến nhất để làm cho một số đoạn code của bạn dễ hiểu hơn và rõ ràng hơn là trích xuất một lớp. Tuy nhiên, nhiều lần lớp này không dành cho việc sử dụng một cách public. Đó là một chi tiết thực hiện của một lớp lớn hơn. Nó không nên được sử dụng được bất cứ ai khác, nhưng mô-đun trong đó đã được định nghĩa. Vậy làm thế nào để chúng ta che giấu được lớp học đó để những người khác không sử dụng? Đôi khi nó có ý nghĩa, để xác định các lớp riêng tư. Ví dụ nếu logic đặc biệt đã được di chuyển vào một lớp liên quan cho các lý do đóng gói. Sau đó, không cần phải rời khỏi lớp là công khai. Một lớp Product là một ví dụ hợp lý. Mỗi sản phẩm được đặc trưng bởi số serial cụ thể của nó. Tuy nhiên, lớp Sản phẩm không chịu trách nhiệm tạo ra số sê-ri. Nó là để đóng gói logic vào một lớp Serial riêng biệt. Thậm chí nhiều hơn, nếu số serial chứa logic thêm nữa:

class Product
  class Serial
    def initialize
      @date = Date.today
    end

    def code
      "#{@date}/#{object_id}"
    end
  end

  attr_reader :serial

  def initialize
    @serial = Serial.new
  end

  def code
    serial.code
  end
end

Lớp Product có thể sử dụng Serial một cách tự do: Một Product tạo mới với Serrial

Product.new.code
# => "2017-06-11/32713960"

Mặc dù lớp Serial có thể truy cập bên ngoài:

Product::Serial.new
# => #<Product::Serial:0x00000002be1548 ... >

Sử dụng private_constant

class Product
  class Serial
    def initialize
      @date = Date.today
    end

    def code
      "#{@date}/#{object_id}"
    end
  end

  # explizit privat:
  private_constant :Serial

  attr_reader :serial

  def initialize
    @serial = Serial.new
  end

  def code
    serial.code
  end
end

Lớp Serial được khai báo riêng bằng cách sử dụng Module # private_constant. Đó là lý do tại sao nó không thể được instantiated trực tiếp nữa:

Product::Serial.new
# => NameError: private constant Product::Serial referenced

Vì vậy, Product là công khai mà bạn phơi bày cho các phần khác của hệ thống và Product :: Serial chỉ là một chi tiết thực hiện. Bạn cũng có thể không thử trực tiếp Product :: Serial trực tiếp, nhưng thông qua Product công khai mà khách hàng sẽ sử dụng.

0