在類別定義里使用一致的結(jié)構(gòu)。
class Person
# 首先是 extend 與 include
extend SomeModule
include AnotherModule
# 接著是常量
SOME_CONSTANT = 20
# 接下來是屬性宏
attr_reader :name
# 跟著是其它的宏(如果有的話)
validates :name
# 公開的類別方法接在下一行
def self.some_method
end
# 初始化方法在類方法和實(shí)例方法之間
def initialize
end
# 跟著是公開的實(shí)例方法
def some_method
end
# 受保護(hù)及私有的方法,一起放在接近結(jié)尾的地方
protected
def some_protected_method
end
private
def some_private_method
end
end
如果某個(gè)類需要多行代碼,則不要嵌套在其它類中。應(yīng)將其獨(dú)立寫在文件中,存放以包含它的類的的名字命名的文件夾中。
# 差
# foo.rb
class Foo
class Bar
# 30個(gè)方法
end
class Car
# 20個(gè)方法
end
# 30個(gè)方法
end
# 好
# foo.rb
class Foo
# 30個(gè)方法
end
# foo/bar.rb
class Foo
class Bar
# 30個(gè)方法
end
end
# foo/car.rb
class Foo
class Car
# 20個(gè)方法
end
end
傾向使用模塊,而不是只有類別方法的類。類別應(yīng)該只在產(chǎn)生實(shí)例是合理的時(shí)候使用。
# 差
class SomeClass
def self.some_method
# 省略函數(shù)體
end
def self.some_other_method
end
end
# 好
module SomeClass
module_function
def some_method
# 省略函數(shù)體
end
def some_other_method
end
end
當(dāng)你想將模塊的實(shí)例方法變成類別方法時(shí),偏愛使用?module_function
?勝過?extend self
。
# 差
module Utilities
extend self
def parse_something(string)
# 做一些事
end
def other_utility_method(number, string)
# 做另一些事
end
end
# 好
module Utilities
module_function
def parse_something(string)
# 做一些事
end
def other_utility_method(number, string)
# 做另一些事
end
end
當(dāng)設(shè)計(jì)類型層級時(shí),確認(rèn)它們符合?Liskov 替換原則。
永遠(yuǎn)替類型提供一個(gè)適當(dāng)?shù)?to_s
?方法給來表示領(lǐng)域模型。
class Person
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def to_s
"#{@first_name #@last_name}"
end
end
使用?attr
?系列函數(shù)來定義瑣碎的訪問器或 mutators。
# 差
class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
def last_name
@last_name
end
end
# 好
class Person
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
end
不要使用?attr
。使用?attr_reader
?和?attr_accessor
。
# 差 - ruby 1.9 中就不推薦了
attr :something, true
attr :one, :two, :three # behaves as attr_reader
# 好
attr_accessor :something
attr_reader :one, :two, :three
考慮使用?Struct.new
,它替你定義了那些瑣碎的訪問器(accessors),構(gòu)造器(constructor)以及比較操作符(comparison operators)。
# 好
class Person
attr_reader :first_name, :last_name
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
end
# 更好
Person = Struct.new(:first_name, :last_name) do
end
不要擴(kuò)展?Struct.new
。它已經(jīng)是個(gè)類了。對它擴(kuò)展不但引入了無意義的類的層次也會在該文件多次被require時(shí)出現(xiàn)奇怪的錯(cuò)誤。
考慮加入工廠方法以提供附加的有意義的方式來生成一個(gè)特定的類實(shí)例。
class Person
def self.create(options_hash)
# body omitted
end
end
傾向使用鴨子類型?而不是繼承。
## 差
class Animal
# 抽象方法
def speak
end
end
# 繼承超類
class Duck < Animal
def speak
puts 'Quack! Quack'
end
end
# 繼承超類
class Dog < Animal
def speak
puts 'Bau! Bau!'
end
end
## 好
class Duck
def speak
puts 'Quack! Quack'
end
end
class Dog
def speak
puts 'Bau! Bau!'
end
end
由于類變量在繼承中產(chǎn)生的“討厭的”行為,避免使用類變量(@@
)。
class Parent
@@class_var = 'parent'
def self.print_class_var
puts @@class_var
end
end
class Child < Parent
@@class_var = 'child'
end
Parent.print_class_var # => will print "child"
如同你所看到的,在類型層級中的所有類其實(shí)都共享單獨(dú)一個(gè)類變量。通常情況下應(yīng)該傾向使用實(shí)例變量而不是類變量。
依據(jù)方法的目的用途指定適當(dāng)?shù)目梢妼蛹墸?code>private,protected
)。別把所有方法都設(shè)為?public
(方法的缺省值)。我們現(xiàn)在是在寫“Ruby”,不是“Python”。
將?public
,protected
,private
?和被應(yīng)用的方法定義保持一致的縮排。在上下各留一行來強(qiáng)調(diào)這個(gè)可見性應(yīng)用于之后的所有方法。
class SomeClass
def public_method
# ...
end
private
def private_method
# ...
end
def another_private_method
# ...
end
end
使用?def self.method
?來定義方法。在代碼重構(gòu)時(shí)如果修改類名也無需重復(fù)多次修改了。
class TestClass
# 差
def TestClass.some_method
# 省略方法體
end
# 好
def self.some_other_method
# 省略方法體
end
# 當(dāng)你需要定義很多個(gè)類時(shí),另一種便捷的方式
class << self
def first_method
# 省略方法體
end
def second_method_etc
# 省略方法體
end
end
end
更多建議: