수색…
소개
디자인 패턴은 코드를 읽기 쉽 도록 유지하는 좋은 방법입니다. DRY는 반복하지 않는다는 의미입니다. 아래에서 가장 중요한 디자인 패턴에 대한 예를 찾을 수 있습니다.
비고
소프트웨어 엔지니어링에서 소프트웨어 설계 패턴은 소프트웨어 설계의 주어진 상황에서 일반적으로 발생하는 문제에 대한 일반적인 재사용 가능한 솔루션입니다.
싱글 톤 패턴
Singleton 패턴은 클래스의 인스턴스화를 하나의 객체로 제한하는 디자인 패턴입니다. 첫 번째 객체가 생성 된 후에 객체를 호출 할 때마다 동일한 객체에 대한 참조를 반환합니다.
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 */);
모듈 패턴 공개
계좌 배양 패턴은 모듈 패턴의 변형입니다. 주요 차이점은 모든 멤버 (private 및 public)가 클로저 내에 정의되고 반환 값은 함수 정의가 포함되지 않은 객체 리터럴이며 멤버 데이터에 대한 모든 참조는 반환 된 객체 대신 직접 참조를 통해 수행된다는 것입니다.
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 */);
프로토 타입 패턴 공개
드러내는 패턴의 이러한 변형은 생성자를 메소드로 분리하는 데 사용됩니다. 이 패턴을 통해 객체 지향 언어와 같은 자바 스크립트 언어를 사용할 수 있습니다.
//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에서 프로토 타입 상속을 기본적으로 지원하기 때문에이 토폴로지를 모방하는 데 시간과 노력을 들이지 않아도됩니다.
프로토 타입에 메소드 생성하기
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
cowFactory
함수가 cowFactory
함수 내에서 닫혀 formalName
마지막 행에서 오류가 발생합니다. 이것은 종결 이다.
또한 팩토리는 함수이기 때문에 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 )