2010-11-18 46 views
14

Phương pháp và phương pháp lớp học trong eigenclass (hoặc metaclass) của lớp đó chỉ là hai cách để định nghĩa một thứ?Phương pháp lớp Ruby so với phương pháp trong Eigenclasses

Nếu không, sự khác biệt là gì?

class X 
    # class method 
    def self.a 
    "a" 
    end 

    # eigenclass method 
    class << self 
    def b 
     "b" 
    end 
    end 
end 

X.b hoạt động khác nhau theo bất kỳ cách nào?

tôi nhận ra rằng tôi có thể ghi đè lên hoặc các phương pháp lớp học bí danh bằng cách mở eigenclass:

irb(main):031:0> class X; def self.a; "a"; end; end 
=> nil 
irb(main):032:0> class X; class << self; alias_method :b, :a; end; end 
=> #<Class:X> 
irb(main):033:0> X.a 
=> "a" 
irb(main):034:0> X.b 
=> "a" 
irb(main):035:0> class X; class << self; def a; "c"; end; end; end 
=> nil 
irb(main):036:0> X.a 
=> "c" 

Trả lời

11

Hai phương pháp là tương đương. phiên bản 'eigenclass' là hữu ích cho việc sử dụng các phương pháp attr_ *, ví dụ:

class Foo 
    @instances = [] 
    class << self; 
    attr_reader :instances 
    end 
    def initialize 
    self.class.instances << self 
    end 
end 

2.times{ Foo.new } 
p Foo.instances 
#=> [#<Foo:0x2a3f020>, #<Foo:0x2a1a5c0>] 

Bạn cũng có thể sử dụng define_singleton_method để tạo ra phương pháp trên lớp:

Foo.define_singleton_method :bim do "bam!" end 
+1

Đây là câu trả lời thực sự xuất sắc về singletons –

6

Trong Ruby có thực sự là không có như vậy những thứ như phương pháp lớp học. Vì mọi thứ đều là một đối tượng trong Ruby (bao gồm cả các lớp), khi bạn nói def self.class_method, bạn chỉ thực sự định nghĩa một phương thức singleton trên cá thể của lớp Class. Vì vậy, để trả lời câu hỏi của bạn, hãy nói

class X 
    def self.a 
    puts "Hi" 
    end 

    class << self 
    def b 
     puts "there" 
    end 
    end 
end 

X.a # => Hi 
X.b # => there 

là hai cách để nói cùng một điều. Cả hai phương thức này chỉ là singeton (eigen, meta, ghost, hoặc bất cứ thứ gì bạn muốn gọi chúng) các phương thức được định nghĩa trong cá thể đối tượng Class của bạn, trong ví dụ của bạn là X. Chủ đề này là một phần của metaprogramming, đó là một chủ đề thú vị, rằng nếu bạn đã sử dụng Ruby một thời gian, bạn nên kiểm tra. Các lập trình viên thực dụng có một tuyệt vời book trên metaprogramming rằng bạn chắc chắn nên xem xét nếu bạn quan tâm đến chủ đề.

+2

Không đồng ý về "Không có điều như phương pháp lớp học". Smalltalk đã tồn tại lâu hơn, và cũng là OO thuần túy và họ sử dụng thuật ngữ phương pháp lớp học mọi lúc. Nói phương thức lớp ít gây nhầm lẫn hơn 'singleton' vì phương thức sau là mẫu thiết kế chứ không phải thuộc tính của ngôn ngữ. –

+1

Tôi có thể nhận được một giải thưởng cho necromancy ở đây, nhưng tôi mạnh mẽ đồng ý về "không có những điều như phương pháp lớp học". Nếu bạn định nghĩa một phương thức trên eigenclass của đối tượng, và đối tượng đó là một thể hiện của 'Dog', bạn không gọi phương thức đó là một phương thức dog. – ggPeti

+0

Nếu bạn đánh dấu một phương thức bằng hàm ': private_class_method', nó chắc chắn sẽ cố gắng làm cho bạn nghĩ nó như là một phương thức lớp. –

3

Tuy nhiên, một Necromancer đây để khai quật câu hỏi cũ này ... Một điều bạn có thể không nhận thức được rằng đánh dấu một phương pháp học như private (sử dụng từ khóa riêng thay vì :private_class_method) khác với đánh dấu một phương pháp eigenclass như vậy . :

class Foo 
    class << self 
    def baz 
     puts "Eigenclass public method." 
    end 

    private 
    def qux 
     puts "Private method on eigenclass." 
    end 
    end 
    private 
    def self.bar 
    puts "Private class method." 
    end 
end 

Foo.bar 
#=> Private class method. 
Foo.baz 
#=> Eigenclass public method. 
Foo.qux 
#=> NoMethodError: private method `qux' called for Foo:Class 
# from (irb) 

Ví dụ sau sẽ làm việc như thế nào trước đó dự định:

class Foo 
    class << self 
    def baz 
     puts "Eigen class public method." 
    end 

    private 
    def qux 
     puts "Private method on eigenclass." 
    end 
    end 
    def bar 
    puts "Private class method." 
    end 
    private_class_method :bar 
end 
Foo.bar 
#=> NoMethodError: private method `bar' called for Foo:Class 
#  from (irb) 
Foo.baz 
#=> Eigen class public method. 
Foo.qux 
#=> NoMethodError: private method `qux' called for Foo:Class 
#  from (irb) 
1

Hầu hết các phương pháp dụ được sử dụng trong Ruby là phương pháp toàn cầu. Điều đó có nghĩa là chúng có sẵn trong mọi trường hợp của lớp mà chúng được định nghĩa. Ngược lại, một phương thức singleton được thực hiện trên một đối tượng duy nhất.

Có một mâu thuẫn rõ ràng. Ruby lưu trữ các phương thức trong các lớp và tất cả các phương thức phải được liên kết với một lớp. Đối tượng mà trên đó một phương thức singleton được định nghĩa không phải là một lớp (nó là một thể hiện của một lớp). Nếu chỉ có các lớp có thể lưu trữ các phương thức, làm thế nào một đối tượng có thể lưu trữ một phương thức singleton? Khi một phương thức singleton được tạo, Ruby sẽ tự động tạo một lớp ẩn danh để lưu trữ phương thức đó. Những lớp ẩn danh này được gọi là metaclasses, còn được gọi là lớp singleton hoặc eigenclasses. Phương pháp singleton được kết hợp với metaclass, lần lượt, được kết hợp với đối tượng mà phương thức singleton được định nghĩa.

Nếu nhiều phương thức đơn được xác định trong một đối tượng, tất cả chúng đều được lưu trữ trong cùng một metaclass.

class Zen 
end 

z1 = Zen.new 
z2 = Zen.new 

def z1.say_hello # Notice that the method name is prefixed with the object name 
    puts "Hello!" 
end 

z1.say_hello # Output: Hello! 
z2.say_hello # Output: NoMethodError: undefined method `say_hello'… 

Trong ví dụ trên, phương thức say_hello được xác định trong cá thể z1 của lớp Zen chứ không phải thể hiện z2.

Ví dụ sau cho thấy một cách khác để xác định phương thức singleton, với cùng một kết quả.

class Zen 
end 

z1 = Zen.new 
z2 = Zen.new 

class << z1 
    def say_hello 
    puts "Hello!" 
    end 
end 

z1.say_hello # Output: Hello! 
z2.say_hello # Output: NoMethodError: undefined method `say_hello'… 

Trong ví dụ trên, lớp < < z1 thay đổi tự hiện tại để trỏ đến metaclass của đối tượng z1; sau đó, nó định nghĩa phương thức say_hello trong metaclass.

Cả hai ví dụ trên đều nhằm minh họa cách thức hoạt động của phương thức singleton. Tuy nhiên, có một cách dễ dàng hơn để định nghĩa một phương thức singleton: sử dụng phương thức dựng sẵn có tên là define_singleton_method.

class Zen 
end 

z1 = Zen.new 
z2 = Zen.new 

z1.define_singleton_method(:say_hello) { puts "Hello!" } 

z1.say_hello # Output: Hello! 
z2.say_hello # Output: NoMethodError: undefined method `say_hello'… 

Chúng tôi đã học sớm hơn rằng các lớp cũng là đối tượng (các phiên bản của lớp được tạo sẵn có tên là Lớp). Chúng tôi cũng đã học về các phương pháp lớp học. Các phương thức lớp không có gì khác hơn là các phương thức singleton được liên kết với một đối tượng lớp.

Một ví dụ nữa:

class Zabuton 
    class << self 
    def stuff 
     puts "Stuffing zabuton…" 
    end 
    end 
end 

Tất cả các đối tượng có thể có metaclasses. Điều đó có nghĩa là các lớp học cũng có thể có metaclasses. Trong ví dụ trên, lớp < < tự sửa đổi bản thân để nó trỏ đến lớp siêu lớp của lớp Zabuton. Khi một phương thức được định nghĩa mà không có bộ nhận rõ ràng (lớp/đối tượng mà phương thức sẽ được định nghĩa), nó được định nghĩa ngầm trong phạm vi hiện tại, nghĩa là giá trị hiện tại của tự. Do đó, phương thức công cụ được định nghĩa trong metaclass của lớp Zabuton. Ví dụ trên chỉ là một cách khác để định nghĩa một phương thức lớp.

Đọc thêm tại this post about Ruby Classes.

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