當我們在開發專案時,你終究會遇到需在自身類別中使用其它類別所實例化的物件來做一些事情。但每當你在自身類別中引用其它類別時,實際上也是在對其它類別產生了相依性,並且提高了這個類別對其他程式碼的耦合度,這樣的情況並不是我們所樂見的。當我們必須對其它類別產生相依性且無可避免的時候呢?我們該怎麼處理類似的情況呢?這時候我們可以選擇孤立其它類別在自身類別中。接下來我們將使用實例來探討該如何處理類似的情況。
繼續我們先前的車子範例,如果我們要繼續打造這台車子,但是輪子需要乘載更多的資訊量呢?是時候考慮將輪子獨立出來自成一類來處理相關的資訊了。我們先將程式範例改寫為如下:
class Car
attr_reader :name, :color, :wheels, :type
def initialize(info = {})
@name = info[:name] || '未命名'
@color = info[:color] || '藍'
@type = info[:type] || '房車'
@wheels = info[:wheels] || Wheels.new
end
def info
puts "#{name},這輛車子是#{@color}色的,類型為#{@type},輪子有#{@wheels.quantity}個。"
end
end
class Wheels
attr_reader :color, :quantity, :type
def initialize(info = {})
@color = info[:color] || '黑'
@quantity = info[:quantity] || 4
@type = info[:type] || '道路'
end
def info
puts "這台車的輪胎規格為#{@type}胎,顏色為#{@color}色,共有#{@quantity}個輪胎。"
end
end
compact_car = Car.new(name: '發財車', type: '貨車')
compact_car.info # => 發財車,這輛車子是藍色的,類型為貨車,輪子有4個。
compact_car.wheels.info # => 這台車的輪胎規格為道路胎,顏色為黑色,共有4個輪胎。
super_car = Car.new(name: '佛拉利', color: '紅', type: '跑車',
wheels: Wheels.new(color: '銀', type: '賽道'))
super_car.info # => 佛拉利,這輛車子是紅色的,類型為跑車,輪子有4個。
super_car.wheels.info # => 這台車的輪胎規格為賽道胎,顏色為銀色,共有4個輪胎。
當我們決定把 Wheels
獨立拆出來成為一個類別時,我們的 Car
類別很自然的會期待在初始化物件時接收一個 Wheels
類別的實體並存入一個實體變數當中,以待需要時取得 Wheels
的實體並使用它。我們所講述的正是這行程式碼:
@wheels = info[:wheels] || Wheels.new
還記得先前所講的嗎?當我們在自身類別中引用外部類別時,我們就對它產生了依賴性與提高了耦合度。我們現在對 Wheels
這個類別產生了依賴。現在來說你可能會想一切都在我的掌控之中因為 Wheels
這個類別是我所寫的,我很清楚它會如何運作。但是稍等一下⋯⋯假設今天的專案是多人協作的呢?Wheels
這個類別是同事所寫的呢?你能確保在接下來的專案開時間下,Wheels
對這個類別呼叫 Wheels.new
所需要傳入的參數以及他所提供的 API info
不會有所變動嗎?它仍然是可靠的嗎?(謎之聲:那個誰誰誰?你幹嘛沒事去改動傳入的參數啦!?這樣害我程式整組壞光光惹 Q_Q,說好的可靠性呢?)
我們該怎麼解處理這樣的問題呢?解決提出問題的人?(大誤
喘口氣吧~在下篇文章將接續探討該如何解決這種情境。我們下回分曉!