Rubyのdelegate
あるクラスのメソッドを、依存するインスタンスに委譲するメソッドです。 次のように使います。
delegate [:first, :last] => :@arr
ぱっと見不思議ですが、ハッシュ { [:first, :last] => :@arr }
が引数の関数呼び出しです。
first
メソッドとlast
メソッドを@arr
インスタンスに委譲しています。
JavaScriptの実装
似たようなことをJavaScriptでやりたいなと思いました。
次のように実装しました。
function forwardMethods(self, getTargetFunction, methods) { for (const method of methods) { self[method] = (...args) => { const target = getTargetFunction() console.assert(target[method], `No ${method} method to forward`, target) return target[method].apply(target, args) } } }
使い方は次の通りです。
forwardMethods(this, () => this._clipBoard, [ 'copyEntities', 'cutEntities', 'pasteEntities' ])
第一引数がthisなのは、クラスのコンストラクタ関数の中で使う想定だからです。 オブジェクトを指定すれば良いので、コンストラクタの外でも使えます。
第二引数がコールバック関数なのは、委譲先を動的に解決したかったからです。
関数名にはdelegateではなくforwardを使いました。 JavaScript界には、次のようにたくさんのdelegateがいて紛らわしいからです。
- jQueryのdelegateをはじめとするイベントのdelegate
- C#のdelegateのようなイベントハンドラーを管理するもの
- オブジェクト指向の委譲
参考
Mixins, Forwarding, and Delegation in JavaScript
このブログを眺めながら、APIとか実装を考えました。
delega - npm
実装後に、npmなら似たようなパッケージがあるだろうと、探したnpmパッケージです。 APIが完全に一致していました。 まあまあ、汎用的なAPI設計ができていたようです。