メインコンテンツへ移動

コンストラクタパターン_JavaScript デザインパターン 1

無料2015-07-10#JS#Design_Pattern#JavaScript设计模式#构造器模式#Constructor_Pattern

コンストラクタパターンは『JavaScript デザインパターン』一书で紹介される最初のパターンで、内容は非常に薄く、本に対して少し失望しました。しかし問題ありません、他のものを参考にしてこの内容を豊かにできます

はじめに

始める前に、このパターンの名前に注目しましょう:Constructor(コンストラクタ)パターン。GoF の 23 のデザインパターンにはこれがなく、名前の字面上で最も似ているのは Builder(ビルダー)パターンです。しかし Builder の実際の意味は书中で紹介されているものとは異なります:

ビルダーパターン(Builder):組合せ構造(木構造)の構築プロセスをカプセル化するために使用され、イテレータパターンと同様に、組合せ構造の内部実装を隠蔽し、組合せ構造を作成するための一組のインターフェースのみを提供する

([黯羽轻扬:デザインパターン总结](/articles/デザインパターン总结(《head-first デザインパターン》学習总结)/) より引用)

したがって、Constructor は JavaScript が class に基づく継承を提供していないことを補うために提案されたデザインパターンを指すはずで、それなら神秘性はありません

一.Constructor(コンストラクタ)パターン

书中的実例から見ると、コンストラクタパターンは属性の共有を実現するために使用されます。いわゆる「コンストラクタパターン」は実際には基本的な常識に過ぎません:プライベート属性をコンストラクタ関数内で定義し、パブリック属性をプロトタイプオブジェクト上で定義します。コードは以下の通り:

function Fun(arg) {
    this.arg = arg;

    // プライベート属性
    var attr = 1;
    function fun() {
        // ...
    }
}
// パブリック属性(プロトタイプオブジェクト上で関数属性を定義するのは、関数が各インスタンス間で共有でき、メモリ占有を減少させるため)
Fun.prototype.fun = function() {
    // ...
}
console.log(new Fun(1).fun === new Fun(2).fun); // true

このようにするのは確かに一定の利点(メモリ占有の減少)がありますが、大きな問題(例えばプロトタイプ参照属性がインスタンス間で共有される)が存在します。著者は引き続き展開せず、単に一句话の常識に「デザインパターン」のラベルを貼って匆匆と終了しました。

JavaScript の継承については、筆者は以前に詳細な説明を行いました。ここでは繰り返しません。黯羽轻扬:JS の 6 種類の継承方式を重新理解 を参照

二.最佳継承方式

JavaScript の継承方式を重新梳理し、直接コードを見ます。コード自身が語ります:

/* 親クラス */
function Super(arg) {
    this.arg = arg;

    // プライベート属性
    var attr = 1;
    function fun() {
        // ...
    }
}

// パブリック属性(プロトタイプオブジェクト上で関数属性を定義するのは、関数が各インスタンス間で共有でき、メモリ消耗を減少させるため)
Super.prototype.fun = function() {
    // ...
}
/* 子クラス */
function Sub(arg, newArg) {
    // 親クラスインスタンス属性を継承
    Super.call(this, arg);

    // 子クラスインスタンス属性を初期化
    this.newArg = newArg;
    // ...
}
// 欠点:親クラスコンストラクタにパラメータを渡せない
// Sub.prototype = new Super();

function F() {} // 空関数、借りて子供を産む(beget)
F.prototype = Super.prototype;
var proto = new F();    // 「純潔な」子供を取得
Sub.prototype = proto;  // 親クラスプロトタイプ属性を継承

// test
var sub = new Sub(1, 2);
// 親クラス属性を出力
console.log(sub.arg);   // 1
console.log(new Sub(3, 4).fun === new Sub(5, 6).fun);   // true

上記の実装にはまだ一点の瑕疵が存在し、proto.constructor = Sub; のこの一行が欠けています。これによりsub.constructor は Super を指しており、実際には Sub を指すことを希望しています。欠けているその行を添えれば良いです

三.少しの無駄話

3 ヶ月前の面接で JS の継承を問われて詰まりました。その後 6 種類の継承方式を重新理解し、現在 3 ヶ月が経過し、印象は非常に深刻です(上記のコードを直接書きました。一点の瑕疵は存在しますが。。)。これにより、時間を費やして一つのものを理解することは非常に有用であることがわかります。否则現在きっと「Constructor(コンストラクタ)パターン」の大帽子に唬されたでしょう

参考資料:

コメント

コメントはまだありません

コメントを書く