07/09/2018, 16:04

Mẹo sử dụng một class để truy suất config var

Rất phổ biến ở các app có một class để truy xuất các thuộc tính được cài sẵn, vd các thông tin về DB URL, vv. Thường thì các thông tin này được lưu vào trong một file YAML rồi được class này đọc, nhưng trong bài hướng dẫn này mình xin hardcode vào trong class luôn để đơn giản hoá nội dung. Việc ...

Rất phổ biến ở các app có một class để truy xuất các thuộc tính được cài sẵn, vd các thông tin về DB URL, vv. Thường thì các thông tin này được lưu vào trong một file YAML rồi được class này đọc, nhưng trong bài hướng dẫn này mình xin hardcode vào trong class luôn để đơn giản hoá nội dung.

Việc đầu tiên là viết một class:

module LệRơi
  class Configuration
    def definitions
      @defintions ||= {
        :top_hit => "Tình đơn phương"
      }
    end

    def definition_for(key)
      definitions[key]
    end
  end
end

Có thể thấy ở trên đây là một class Plain Old Ruby rất chi đơn giản, nó bao gồm 2 hàm chính:

  • #definitions - nơi bạn lưu các config var, đây là một hash
  • #definition_for - hàm để truy xuất config dựa theo tên key, nếu trùng thì trả về giá trị không thì trả về nil

Truy xuất đơn giản với

LệRơi::Configuration.new.definition_for(:top_hit)
# => "Tình đơn phương"
# nghe mà muốn khóc

Phiên bản đầu tiên coi như là xong. Thực sự chúng ta có thể dừng ở đây nhưng chúng ta có thể cải tiến code này. Bạn có thể thấy việc kiến tạo object mỗi lần truy xuất thật là tốn kém, nó dẫn đến nhiều object config đc tạo ra mà không cần thiết. Để kiếm chứng, chúng ta kiểm tra object_id của instance:

LệRơi::Configuration.new.definition_for(:top_hit).object_id
# => 70132340658520

LệRơi::Configuration.new.definition_for(:top_hit).object_id
# => 70132337071440

Kểt quả id của instance khác nhau, chứng tỏ là instance mới đc tạo ra.

Thế nên chúng ta sẽ refactor lại code trên để chỉ tạo ra một object khi truy xuất:

module LệRơi
  class Configuration
    def self.instance
      @instance ||= self.new
    end

    # code cũ ở đây

Và truy xuất bây giờ sẽ thông qua hàm .instance:

LệRơi::Configuration.instance.definition_for(:top_hit)
# => "Tình đơn phương"

Hãy xem bao nhiêu instance mới được tạo ra nhé:

LệRơi::Configuration.instance.definition_for(:top_hit).object_id
# => 70132336967820

LệRơi::Configuration.instance.definition_for(:top_hit).object_id
# => 70132336967820

Dựa trên kết quả object ID trùng, chúng ta có thể thấy chỉ có một instance đc tạo ra. :)

Không dừng ở đó, chúng ta có thể refactor code này với mixin Singleton của Ruby, chúng ta xoá bỏ hàm .instance và thay vào bằng:

require 'singleton'

module LệRơi
  class Configuration
    include Singleton

    def definitions
      @defintions ||= {
        :top_hit => "Tình đơn phương"
      }
    end

    def definition_for(key)
      definitions[key]
    end
  end
end

Xong, mixin Singleton cung cấp interface API instance và làm cùng chức năng như hàm .instance của chúng ta.

Hi vọng mọi người học thêm đc một mẹo hay để viết code Ruby đẹp. Rất cảm ơn mọi người, mong mọi người tiếp tục ủng hộ Lệ Rơi để Rơi tiếp tục cho ra các sáng tác lôi cuốn lòng người.

0