2009-05-20 22 views
7

Tôi có thể hiểu tại sao bạn cần một biến lớp để theo dõi những thứ như tổng số đối tượng đã được khởi tạo trong lớp đó.Bạn đã bao giờ sử dụng "biến thể hiện lớp" trong bất kỳ mã Ruby nào của bạn chưa?

Và tôi có thể hiểu tại sao bạn cần một biến thể hiện ví dụ để lưu trữ các thuộc tính của một đối tượng cụ thể trong lớp đó.

Nhưng biến thể hiện lớp Tôi dường như không thể biện minh được.

Như tôi đã hiểu, chúng giống như biến lớp ngoại trừ chúng là không hiển thị cho các lớp con theo cách biến lớp là.

Dường như việc sử dụng cho mục này sẽ khá hạn chế. Hoặc là tôi sai? Có ai tìm thấy một sử dụng tốt cho các biến thể hiện lớp trong mã của họ? Hay bạn có thể đưa ra một ví dụ về một tình huống mà loại sắc thái này sẽ có giá trị?

Trả lời

4

Giả sử bạn muốn đếm số lượng các trường hợp của một lớp học (không bao gồm các lớp con)

class A 
    @count = 0 
    @@count = 0 
    def self.inherited(subclass) 
    subclass.instance_eval { @count = 0 } 
    end 
    def self.num_instances 
    @count 
    end 
    def self.num_subclass_instances 
    @@count 
    end 
    def self.new 
    @count += 1 
    @@count += 1 
    super 
    end 
end 
class B < A 
end 
class C < B 
end 

A.new 
B.new 
A.new 
B.new 
B.new 
C.new 

A.num_instances #=> 2 
A.num_subclass_instances #=> 6 
B.num_instances #=> 3 
B.num_subclass_instances #=> 6 
C.num_instances #=> 1 
C.num_subclass_instances #=> 6 

Bạn không thể sử dụng các biến lớp học, vì đó là chia sẻ giữa tất cả lớp học và các lớp con của nó. Lưu ý cách các thay đổi được thực hiện cho @@count bởi BC được phản ánh trong A, nhưng @count không được chia sẻ.

Nói chung, mặc dù, nó có thể rất hữu ích để lưu trữ bất kỳ cài đặt cụ thể theo lớp nào. _why sử dụng nó trong Dwemthy's Array để chỉ định giá trị ban đầu cho các thuộc tính dụ và nó xuất hiện rất nhiều khi thực hiện lập trình siêu lập trình ruby.

+0

Cảm ơn. Ví dụ tuyệt vời (s).Vì vậy, về cơ bản, nếu chúng tôi chỉ có các biến lớp, chúng tôi sẽ không thể thực hiện những việc như số lượng được bản địa hóa này cho A, B và C - chúng tôi sẽ bị mắc kẹt tương đương với num_subclass_instances của bạn. Tôi nghĩ rằng tôi nhận được nó ngay bây giờ. Phần duy nhất của mã của bạn mà tôi không hiểu là: def self.inherited (subclass) subclass.instance_eval {@count = 0} end. Cái đó làm cái gì? –

+0

Vì vậy, tôi đã khởi tạo A @count theo định nghĩa của A, nhưng tôi cần phải khởi tạo @count thành 0 cho tất cả các lớp con của A, điều đó là mã gì. Khi A được thừa kế bởi 'lớp con', chúng ta mở lớp con và khởi tạo @count của nó thành 0. Hãy thử loại bỏ nó, và bạn sẽ thấy NoMethodErrors khi B và C được khởi tạo, vì Ruby sẽ không biết cách thêm 1 vào nil (giá trị mặc định của @count nếu không được khởi tạo) – rampion

+0

OK. Cảm ơn. Nhân tiện, tôi đang tìm kiếm tài liệu trên example_eval và tìm thấy nó cho 1.87 (http://www.rubybrain.com/api/ruby-1.8.7/doc/index.html?a=M000295&name=instance_eval) nhưng có vẻ giống như nó đã biến mất từ ​​1.90 (http://www.rubybrain.com/api/ruby-1.9.0.2/doc/index.html?a=C00000022&name=Object). –

3

Biến lớp được chia sẻ trên tất cả các phiên bản của một lớp, bao gồm tất cả các lớp con. Đôi khi biến này trên một hệ thống phân cấp là chính xác những gì cần thiết, nhưng đôi khi bạn có thể thích một biến khác nhau cho mỗi lớp. Không giống như các biến lớp, các biến cá thể lớp sẽ có các giá trị khác nhau cho từng đối tượng lớp.

http://martinfowler.com/bliki/ClassInstanceVariable.html

3

Có, thực sự tôi có. Đây chỉ là một chút sửa đổi và cắt tỉa từ những gì tôi đã có:

class Widget 
    # class instance variable pattern 
    class << self; attr_accessor :color; end 

    def show_color() 
    "This widget is #{self.class.color}" 
    end 
end 
class WidgetR < Widget 
    @color = "Russet" 
end 
class WidgetC < Widget 
    @color = "Cordovan" 
end 
class WidgetL < Widget 
    @color = "Liver" 
end 

WidgetR.new.show_color #=> "This widget is Russet" 

Nhưng tôi không chắc nó thực sự cần thiết trong trường hợp tôi đã sử dụng nó. Tôi có thể chỉ cần ghi đè phương pháp. Hoặc cung cấp một phương pháp màu. Hoặc lưu nó trong một biến lớp như là một Hash. Hoặc thậm chí giữ một bản sao trong mỗi trường hợp (ok, đó là một kinda yech). Tôi chắc chắn có những khả năng khác ...

Có nhiều lựa chọn thay thế và cú pháp rất khó xử. Cho rằng tôi đoán các trường hợp mà nó là điều tự nhiên nhất để sử dụng có lẽ là khá hiếm.

Nó có thể giúp bạn cố gắng tái tạo hành vi này với biến lớp và thể hiện và thấy khó đạt được (mặc dù dễ dàng xác định phương pháp, v.v.).

C.J.

Các vấn đề liên quan