prototype.js でデザインパターン - Adapter

Iterator に続きまして、「一皮かぶせて再利用」な Adapter パターンです。クライアントは

var Main = Class.create();
Main.prototype = {
    initialize : function() {},
    main : function () {
        var p = new PrintBanner("Hello, World");
        p.printWeak();
        document.writeln('<br>');
        p.printStrong();
    }
}

といった感じ。PrintBanner クラスは別のレガシーなクラスのアダプタで、インタフェースを肩代わりしてやっていると。

実行結果は

(Hello, World)
*Hello, World*

となります。

今回もやっぱり interface に相当するものは作らずにやってみます。(Adapter パターンで interface がないとなんかちょっとむなしい。)

まずはレガシーなクラス (Adaptee)。クライアントはこいつのインタフェースじゃなくてもっと別のインタフェースを欲しているという状況。

var Banner = Class.create();
Banner.prototype = {
    initialize : function(string) {
        this.string = string;
    },
    showWithParen : function() {
        document.writeln("(" + this.string + ")");
    },
    showWithAster : function() {
        document.writeln("*" + this.string + "*");
    }
}

んでもってこのレガシーなインタフェースを新しいインタフェースとして生まれ変わらせてくれるアダプタ君 (Adapter) は以下。

var PrintBanner = Class.create();
PrintBanner.prototype = (new Banner).extend({
    initialize : function(string) {
        Banner.prototype.initialize.apply(this, arguments);
    },
    printWeak : function() {
        this.showWithParen();
    },
    printStrong : function() {
        this.showWithAster();
    }
});

Adapter パターンでは一枚かぶせるために継承を使う方法と委譲を使う方法といろいろありますが、ここではデザパタ本に習って継承を使う方法で実装してみました。prototype.js の Object.extend を使って Banner を継承してます。

initialize : function(string) {
    Banner.prototype.initialize.apply(this, arguments);
},

と、initialize の中で見慣れないことをやってますが、これはスーパークラスの同一のメソッドを呼ぶ、ということで要は Java で言うところの super()、Perl でいうところの $self->SUPER::new(@_) をやってるといったところ。最初引数の渡し方がわからなくて少し悩んだけど arguments を渡せばいいと prototype.js の中を見てて気付きました。