サーチ…
前書き
デザインパターンは、 コードを読みやすく DRYに保つ良い方法です。 DRYはあなた自身を繰り返さないことを表します 。下には、最も重要なデザインパターンの例があります。
備考
ソフトウェア設計において、ソフトウェア設計パターンは、ソフトウェア設計における所与の状況において一般的に発生する問題に対する一般的な再利用可能な解決策である。
シングルトンパターン
シングルトンパターンは、クラスのインスタンス化を1つのオブジェクトに制限するデザインパターンです。最初のオブジェクトが作成された後は、そのオブジェクトが呼び出されるたびに同じオブジェクトへの参照が返されます。
var Singleton = (function () {
// instance stores a reference to the Singleton
var instance;
function createInstance() {
// private variables and methods
var _privateVariable = 'I am a private variable';
function _privateMethod() {
console.log('I am a private method');
}
return {
// public methods and variables
publicMethod: function() {
console.log('I am a public method');
},
publicVariable: 'I am a public variable'
};
}
return {
// Get the Singleton instance if it exists
// or create one if doesn't
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
使用法:
// there is no existing instance of Singleton, so it will create one
var instance1 = Singleton.getInstance();
// there is an instance of Singleton, so it will return the reference to this one
var instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
モジュールとモジュールパターンの表示
モジュールパターン
Moduleパターンは、パブリックAPIを生成しながらプライベートメンバーをカプセル化する方法を提供する、 創造的かつ構造的なデザインパターンです。これは、公開APIを含むオブジェクトを返す間に( クロージャを使用して)そのスコープでのみ使用可能な変数を定義することを可能にするIIFEを作成することによって達成されます。
これにより、メインロジックを隠し、アプリケーションの他の部分で使用したいインターフェイスだけを公開するためのクリーンなソリューションが提供されます。
var Module = (function(/* pass initialization data if necessary */) {
// Private data is stored within the closure
var privateData = 1;
// Because the function is immediately invoked,
// the return value becomes the public API
var api = {
getPrivateData: function() {
return privateData;
},
getDoublePrivateData: function() {
return api.getPrivateData() * 2;
}
};
return api;
})(/* pass initialization data if necessary */);
モジュールパターンの表示
モジュールの表示パターンは、モジュールパターンの変形です。主な違いは、すべてのメンバー(プライベートおよびパブリック)がクロージャ内で定義され、戻り値が関数定義を含まないオブジェクトリテラルであり、メンバーデータへのすべての参照が、返されたオブジェクトではなく直接参照によって行われることです。
var Module = (function(/* pass initialization data if necessary */) {
// Private data is stored just like before
var privateData = 1;
// All functions must be declared outside of the returned object
var getPrivateData = function() {
return privateData;
};
var getDoublePrivateData = function() {
// Refer directly to enclosed members rather than through the returned object
return getPrivateData() * 2;
};
// Return an object literal with no function definitions
return {
getPrivateData: getPrivateData,
getDoublePrivateData: getDoublePrivateData
};
})(/* pass initialization data if necessary */);
プロトタイプパターンを明らかにする
明らかになるパターンのこの変形は、コンストラクタをメソッドに分離するために使用されます。このパターンは、オブジェクト指向言語のようなjavascript言語を使用することを可能にします:
//Namespace setting
var NavigationNs = NavigationNs || {};
// This is used as a class constructor
NavigationNs.active = function(current, length) {
this.current = current;
this.length = length;
}
// The prototype is used to separate the construct and the methods
NavigationNs.active.prototype = function() {
// It is a example of a public method because is revealed in the return statement
var setCurrent = function() {
//Here the variables current and length are used as private class properties
for (var i = 0; i < this.length; i++) {
$(this.current).addClass('active');
}
}
return { setCurrent: setCurrent };
}();
// Example of parameterless constructor
NavigationNs.pagination = function() {}
NavigationNs.pagination.prototype = function() {
// It is a example of a private method because is not revealed in the return statement
var reload = function(data) {
// do something
},
// It the only public method, because it the only function referenced in the return statement
getPage = function(link) {
var a = $(link);
var options = {url: a.attr('href'), type: 'get'}
$.ajax(options).done(function(data) {
// after the the ajax call is done, it calls private method
reload(data);
});
return false;
}
return {getPage : getPage}
}();
上記のコードは、必要なすべてのページで参照されるように区切られたファイル.js内にある必要があります。これは次のように使用できます:
var menuActive = new NavigationNs.active('ul.sidebar-menu li', 5);
menuActive.setCurrent();
プロトタイプパターン
プロトタイプパターンは、プロトタイプの継承を通じて他のオブジェクトの青写真として使用できるオブジェクトの作成に焦点を当てています。このパターンはJSでのプロトタイプの継承をネイティブにサポートしているため、JavaScriptで本来的に簡単に使用できます。つまり、このトポロジを模倣する時間や労力を費やす必要はありません。
プロトタイプ上のメソッドの作成
function Welcome(name) {
this.name = name;
}
Welcome.prototype.sayHello = function() {
return 'Hello, ' + this.name + '!';
}
var welcome = new Welcome('John');
welcome.sayHello();
// => Hello, John!
プロトタイプ継承
「親オブジェクト」から継承することは、次のパターン
ChildObject.prototype = Object.create(ParentObject.prototype);
ChildObject.prototype.constructor = ChildObject;
ここで、 ParentObject
はプロトタイプ関数の継承元のオブジェクトで、 ChildObject
は新しいオブジェクトです。
親オブジェクトがコンストラクタで初期化する値を持つ場合、子を初期化するときに親コンストラクタを呼び出す必要があります。
これは、 ChildObject
コンストラクタで次のパターンを使用して行います。
function ChildObject(value) {
ParentObject.call(this, value);
}
上記が実装されている完全な例
function RoomService(name, order) {
// this.name will be set and made available on the scope of this function
Welcome.call(this, name);
this.order = order;
}
// Inherit 'sayHello()' methods from 'Welcome' prototype
RoomService.prototype = Object.create(Welcome.prototype);
// By default prototype object has 'constructor' property.
// But as we created new object without this property - we have to set it manually,
// otherwise 'constructor' property will point to 'Welcome' class
RoomService.prototype.constructor = RoomService;
RoomService.prototype.announceDelivery = function() {
return 'Your ' + this.order + ' has arrived!';
}
RoomService.prototype.deliverOrder = function() {
return this.sayHello() + ' ' + this.announceDelivery();
}
var delivery = new RoomService('John', 'pizza');
delivery.sayHello();
// => Hello, John!,
delivery.announceDelivery();
// Your pizza has arrived!
delivery.deliverOrder();
// => Hello, John! Your pizza has arrived!
ファクトリ関数
ファクトリ関数は単にオブジェクトを返す関数です。
ファクトリ関数はnew
キーワードの使用を必要としませんが、コンストラクタのようにオブジェクトを初期化するために使用できます。
ファクトリ関数は、 jQueryやmoment.jsのように、APIラッパーとして使用されることが多いため、 new
を使う必要はありません。
以下は工場機能の最も単純な形式です。引数を取って、それを使ってオブジェクトリテラルで新しいオブジェクトを作ります:
function cowFactory(name) {
return {
name: name,
talk: function () {
console.log('Moo, my name is ' + this.name);
},
};
}
var daisy = cowFactory('Daisy'); // create a cow named Daisy
daisy.talk(); // "Moo, my name is Daisy"
プライベートプロパティとメソッドは、返されたオブジェクトの外側に含めて、簡単に定義できます。これにより、実装の詳細がカプセル化されたままになるため、パブリックインターフェイスのみをオブジェクトに公開することができます。
function cowFactory(name) {
function formalName() {
return name + ' the cow';
}
return {
talk: function () {
console.log('Moo, my name is ' + formalName());
},
};
}
var daisy = cowFactory('Daisy');
daisy.talk(); // "Moo, my name is Daisy the cow"
daisy.formalName(); // ERROR: daisy.formalName is not a function
最後の行は、関数formalName
がcowFactory
関数の内部で閉じられているため、エラーが発生します。これは閉鎖です。
ファクトリは、関数型であるため、関数型プログラミングのプラクティスをJavaScriptで適用するうえで最適な方法です。
作曲のある工場
「相続よりも優先する」は、多くの場合、必要のない行動を継承するのではなく、オブジェクトに振舞いを割り当てるために使用される重要かつ普及したプログラミングの原則です。
行動工場
var speaker = function (state) {
var noise = state.noise || 'grunt';
return {
speak: function () {
console.log(state.name + ' says ' + noise);
}
};
};
var mover = function (state) {
return {
moveSlowly: function () {
console.log(state.name + ' is moving slowly');
},
moveQuickly: function () {
console.log(state.name + ' is moving quickly');
}
};
};
オブジェクトファクトリ
var person = function (name, age) {
var state = {
name: name,
age: age,
noise: 'Hello'
};
return Object.assign( // Merge our 'behaviour' objects
{},
speaker(state),
mover(state)
);
};
var rabbit = function (name, colour) {
var state = {
name: name,
colour: colour
};
return Object.assign(
{},
mover(state)
);
};
使用法
var fred = person('Fred', 42);
fred.speak(); // outputs: Fred says Hello
fred.moveSlowly(); // outputs: Fred is moving slowly
var snowy = rabbit('Snowy', 'white');
snowy.moveSlowly(); // outputs: Snowy is moving slowly
snowy.moveQuickly(); // outputs: Snowy is moving quickly
snowy.speak(); // ERROR: snowy.speak is not a function
抽象的な工場パターン
抽象ファクトリパターンは、作成されている正確なオブジェクトを指定することなく、特定のインスタンスまたはクラスを定義するために使用できる、創造的なデザインパターンです。
function Car() { this.name = "Car"; this.wheels = 4; }
function Truck() { this.name = "Truck"; this.wheels = 6; }
function Bike() { this.name = "Bike"; this.wheels = 2; }
const vehicleFactory = {
createVehicle: function (type) {
switch (type.toLowerCase()) {
case "car":
return new Car();
case "truck":
return new Truck();
case "bike":
return new Bike();
default:
return null;
}
}
};
const car = vehicleFactory.createVehicle("Car"); // Car { name: "Car", wheels: 4 }
const truck = vehicleFactory.createVehicle("Truck"); // Truck { name: "Truck", wheels: 6 }
const bike = vehicleFactory.createVehicle("Bike"); // Bike { name: "Bike", wheels: 2 }
const unknown = vehicleFactory.createVehicle("Boat"); // null ( Vehicle not known )