2007-06-30

上週某天的程式片段.

如果 obj1 想使用 obj2, 但是 obj2 需要一些外面的資源.
如果是 Java, 或許會用所謂的 constructor / setter injection, 從 obj1 塞些物件給 obj2 用.
某些語言會傳 function / function pointer / block 進去.
某些語言, 像 Ruby, 則可以直接由 obj1 "栽贓" method 在 obj2 (精確的說, 是 obj2 的 singleton class)身上, obj2 只管在程式碼需要的地方呼叫預計被插入的 method.
obj1 插入的 method 可以用 closure 暗藏一些將來要用的變數在裡面.

class Object
def my_define_method(name, &block)
(class << self; self; end).send(:define_method, name, block)
end
def inject(newName, obj, oldName = newName)
#puts "#{newName} #{obj} #{oldName}"
my_define_method(newName) { |*args| obj.send(oldName, *args) }
self
end
end


#o1 = Object.new
#def o1.foo; puts "foo.."; end
#def o1.bar(x, y); puts "bar.. #{x + y}"; end
#
#o2 = Object.new
#o2.inject(:foo, o1).inject(:bar2, o1, :bar)
#o2.foo()
#o2.bar2(1, 2)

2 comments:

chliu said...

class Proxy
def initialize(obj)
@object = obj
end

def method_missing(symbol, *args)
@object.send symbol, *args
end
end


a = "hello world"
proxy = Proxy.new(a)
puts proxy.reverse

會不會這種寫法更好

Ren-Shan said...

原來的 code 中, 只 demo 了 inject 的用法, 是我的疏忽 :)

有時需要的不光是像這邊 inject 所作的, 單純的將 obj2 收到的 message forward 給 obj1. 在不少狀況下, 用上面的 my_define_method(名字真爛) 的機會更多.

obj2 對外界說: "請定義這幾個 method 讓我用, 不要塞一個介面太大的物件給我. 我只會用到上面幾個 function, 不想造成額外的 depedency."

obj1 對 obj2 說: "好的, 我會提供剛好你要的東西給你. 你也不需要用額外的 data member 去記憶我傳給你的 method, 我會用語言內建的機制(method on singleton class)掛載給你, 你只管呼叫就好了".

謝謝你的回應 ^^