一口大小的關注點分離
我們常常遇到中等大小行為區塊而想要萃取出來的情況,但只會混入單一類別中。
萃取一個純 Ruby 物件將其封裝起來並與原始物件協同合作或委派,這通常是不錯的選擇;但若沒有額外的狀態需要封裝,或我們對父類別做出 DSL 風格的宣告,那麼引入新的合作者會導致複雜化,而不是簡化。
典型的做法是將所有內容丟進一個巨型類別中,或許附註個提示作為最不壞的方案。在不同檔案中使用模組表示要檢視全局觀點必須不斷仔細篩選。
分離小型關注點的令人不滿意方式
使用提示
class Todo < ApplicationRecord
# Other todo implementation
# ...
## Event tracking
has_many :events
before_create :track_creation
private
def track_creation
# ...
end
end
使用內嵌模組
有雜訊的語法。
class Todo < ApplicationRecord
# Other todo implementation
# ...
module EventTracking
extend ActiveSupport::Concern
included do
has_many :events
before_create :track_creation
end
private
def track_creation
# ...
end
end
include EventTracking
end
混入雜訊流放至其自己的檔案中
一旦我們的行為區塊開始突破捲動到瞭解邊界,我們便會屈服並將其移至一個獨立的檔案。在這種情況下,增加的額外負擔是合理權衡,即使它降低了我們對事情運作機制的直覺式理解。
class Todo < ApplicationRecord
# Other todo implementation
# ...
include TodoEventTracking
end
引入 Module#concerning
我們安撫了混入雜訊後,出現了一種自然而低程序化的方式來分離一口大小的關注點。
class Todo < ApplicationRecord
# Other todo implementation
# ...
concerning :EventTracking do
included do
has_many :events
before_create :track_creation
end
private
def track_creation
# ...
end
end
end
Todo.ancestors
# => [Todo, Todo::EventTracking, ApplicationRecord, Object]
這個小步驟帶來了若干美好的連鎖效應。我們可以
-
一覽我們的類別行為,
-
整理巨型雜物抽屜類別,藉由分離他們的關注點,以及
-
停止仰賴受保護/私有屬性來進行粗糙的「這是內部事物」模組化。
附加 concerning
concerning
支援 prepend: true
參數,它會對關注點使用 prepend
而不是 include
。
方法
執行個體公共方法
concern(topic, &module_definition) 連結
定義關注點的低開銷捷徑。
concern :EventTracking do
...
end
等於
module EventTracking
extend ActiveSupport::Concern
...
end
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/concerning.rb, line 132 def concern(topic, &module_definition) const_set topic, Module.new { extend ::ActiveSupport::Concern module_eval(&module_definition) } end
concerning(topic, prepend: false, &block) 連結
定義一個新關注點並將它混入。
來源:顯示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/concerning.rb, line 114 def concerning(topic, prepend: false, &block) method = prepend ? :prepend : :include __send__(method, concern(topic, &block)) end