Observable で mixin の復習など
Ruby で言う Module はその中でメソドを定義することはできるけれど、オブジェクトを生成して定義されたメソドを呼び出す、などということはできない。ただし include という操作 (というか Module クラスのメソド呼び出し) によりそのクラスで include した module で定義されているメソドを呼び出すことができるようになる。
ええと例えば以下な module があるとして
module Bar def baz end end
みたいな定義だとすると、ここで定義されている baz というメソドを Foo というクラスのオブジェクトから呼び出すことができるようにするには
class Foo include Bar end
してあげれば可能とのこと。
Foo.new.baz
これを使う形でも interface のようなことは可能だけれど定義時点で実装を強制するような事は当り前ですが不可能ですね。
GoF の Observer パターン
これって Observable という module を include してあげれば良い模様。
Observable というのは
- オブジェクトの状態が変わる可能性があり
- 変わったことを他のオブジェクトに通知する必要がある
という場合に適用すれば幸せになれる模様。基本的な使用方法については以下とのこと。
Observableモジュールをincludeしたクラスは Observable#changedメソッドにより更新フラグを立て、 Observable#notify_observers()が呼び出されると 更新フラグが立っている場合はオブザーバに通知する (オブザーバのupdateメソッドを呼び出す)。 Observable#notify_observers()の引数は そのままオブザーバのupdateメソッドに渡される。
Observable より引用
ちなみに
Observable によれば Observable#add_observer は引数で渡されるオブジェクトが update メソドを持っていない場合、例外を、とのこと。おそらくは add_observer される時に、だろうとは思いましたが確認してみました。
irb(main):001:0> require 'observer' => true irb(main):002:0> class AObservable irb(main):003:1> include Observable irb(main):004:1> end => AObservable irb(main):005:0> obj = AObservable.new => #<AObservable:0x00000001207078> irb(main):006:0> class Foo end SyntaxError: (irb):6: syntax error, unexpected keyword_end, expecting '<' or ';' or '\n' (irb):6: syntax error, unexpected $end from /home/rms/.rbenv/versions/1.9.3-p327/bin/irb:12:in `<main>' irb(main):007:0> class Foo irb(main):008:1> end => nil irb(main):009:0> observer = Foo.new => #<Foo:0x000000011c6280> irb(main):010:0> obj.add_observer(observer) NoMethodError: observer does not respond to `update' from /home/rms/.rbenv/versions/1.9.3-p327/lib/ruby/1.9.1/observer.rb:129:in `add_observer' from (irb):10 from /home/rms/.rbenv/versions/1.9.3-p327/bin/irb:12:in `<main>' irb(main):011:0>
微妙ですが、add_observer した時点で update が実装されているかどうかを確認していますね。これってどうやっているのかな。ある意味 interface を強制云々な解とも言えますね。
追記
ありました。Object#respond_to? メソドというものがありました。
しかしこのケイスってのは受け取ったオブジェクトが update というメソドを実装しているかどうか、ということを強制するためのものであってやっぱ何らかの interface 的なナニではないですね。うーん。