我正在撰寫一系列封裝業務邏輯的模塊。它們以任意數量的不同組合作為混合包含在基類中。
這個模塊的每一個都initialize定義了自己的方法,因為它指定了它的必需關鍵字引數。
這個想法是super在這些模塊的initialize方法內部呼叫,所以引數會爬上祖先鏈并到達其他模塊的初始化方法。
但是,這種模式存在一個問題:
module SomeModule
def initialize(arg1: , arg2: , **rest)
@arg1 = arg1
@arg2 = arg2
super
end
end
這實作了模塊化的目標,使得任何擁有這個 Module 的類都將根據需要擁有這兩個引數,并向上傳遞祖先鏈以在其他模塊中進行初始化。但是,鏈中的最后一個模塊將呼叫super,這將引發例外,因為它實際上到達了BasicObject不帶任何引數的 #initialize。
即使你使用super if defined?(super)同樣的問題來了,因為BasicObjecthas這個super方法(#initialize)。
我嘗試使用任何元編程技巧來檢測 super 方法的數量,但method(__method__)會將Method物件回傳給原始類(祖先鏈中的第一個)。
那么,如何實作這個模塊化的目標,讓被包含的模塊不斷呼叫#super它們的 initialize 方法,直到沒有更多的模塊,而不用到達BasicObject#initialize和炸毀,而不必擔心這些模塊的包含順序?
更新:我真的很想避免將例外拯救到BasicObject#initialize.
UPDATE2:呼叫super(**rest)也不會削減它,因為如果祖先鏈中的任何模塊也依賴于已經被前一個模塊吸收的引數,則該引數將在上游丟失。
uj5u.com熱心網友回復:
你可以讓你的類從一些initialize相應實作的基類繼承,例如:
class Base
def initialize(**)
super()
end
end
class MyClass < Base
include SomeModule
end
MyClass.new(arg1: 'foo', arg2: 'bar')
#=> #<MyClass:0x00007fa394843bb0 @arg1="foo", @arg2="bar">
uj5u.com熱心網友回復:
一般地回答你的問題可能會涉及很多元編程的技巧(如果可能的話),這絕對是應該避免的,但我會嘗試為你的特定情況提供答案。
我建議使用prepend而不是include,假設您沒有在這些需要擁有這組initialize方法并在類本身中捕獲最終 super 的類添加任何其他內容:
module M1
def initialize(arg1:, **kwargs)
puts "initialize from M1 with arg1 = #{arg1}"
super
end
end
module M2
def initialize(arg2:, **kwargs)
puts "initialize from M2 with arg1 = #{arg2}"
super
end
end
class C1
prepend M1
prepend M2
def initialize(**kwargs)
puts "initialize from C1"
end
end
C1.new(arg1: 'A1', arg2: 'A2')
在這種情況下,您可以按照您想要的順序添加模塊,最終super將呼叫C1#initialize,因此它將成為您在此呼叫鏈中的停止點。如果你想呼叫另一個super從C1#initialize,只是用變異與引數,并提供正是下一個initialize預期(它不應該知道什么arg1,arg2等等)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/348314.html
標籤:红宝石
