싱글톤 패턴 정의: 클래스에 인스턴스가 하나만 있는지 확인하고 이에 액세스할 수 있는 전역 액세스 지점을 제공합니다.
싱글턴 모드는 일반적으로 사용되는 모드입니다. 스레드 풀, 글로벌 캐시 및 브라우저 창 개체와 같이 종종 하나만 필요한 일부 개체가 있습니다. JS 개발에서는 싱글톤 패턴도 매우 널리 사용됩니다. 로그인 버튼을 클릭하면 로그인 상자가 페이지에 나타나고 이 플로팅 창은 로그인 버튼을 몇 번 클릭하더라도 이 플로팅 창은 한 번만 생성됩니다. 따라서 이 로그인 플로팅 창은 싱글톤 모드에 적합합니다.
1. 싱글턴 모드 사용 시나리오
모드를 사용하기 전에 이 모드의 사용 시나리오를 알아두는 것이 좋습니다. 저는 싱글턴 패턴을 오랫동안 사용해왔는데 아직은 잘 모르겠어요! 이를 사용하면 어떤 이점이 있나요?
1) 네임스페이스를 나누어 사용할 수 있습니다(자주 사용됩니다)
2) 분기 기술을 사용하여 브라우저 간의 차이점을 캡슐화합니다(이전에는 사용해 본 적이 없으며 꽤 새로운 기능입니다)
3) 싱글톤 모드를 사용하면 코드를 보다 일관되게 구성할 수 있어 읽기 및 유지 관리가 더 쉬워집니다. (이 방법도 사용되었습니다.)
2. 가장 기본적인 싱글턴 패턴
가장 간단한 싱글톤은 실제로 객체 리터럴입니다. 관련된 메서드와 속성의 그룹을 함께 구성합니다.
var Singleton = { attr1: true , attr2: 10 , method1 : function(){ alert('我是方法1'); }, method2 : function(){ alert('我是方法2'); } };
이 개체는 수정될 수 있습니다. 속성과 메서드를 추가할 수 있습니다. 삭제 연산자를 사용하여 기존 구성원을 삭제할 수도 있습니다. 이는 실제로 객체 지향 설계 원칙을 위반합니다. 즉, 클래스를 확장할 수는 있지만 수정해서는 안 됩니다. 일부 변수를 보호해야 하는 경우 클로저에 정의할 수 있습니다.
객체 리터럴은 싱글톤을 만드는 방법 중 하나일 뿐입니다. 모든 객체 리터럴이 싱글톤은 아닙니다. 연관 배열을 모방하거나 데이터를 보유하는 데 사용되는 리터럴은 분명히 싱글톤이 아닙니다.
3. 클로저를 사용하여 싱글톤 생성
폐쇄의 주요 목적은 데이터 보호입니다
// 命名空间 var BHX = {} ; BHX.Singleton = (function(){ // 添加自己的私有成员 var a1 = true ; var a2 = 10 ; var f1 = function(){ alert('f1'); } var f2 = function(){ alert('f2'); } // 把块级作用域里的执行结果赋值给我的单例对象 return { attr1: a1 , attr2: a2 , method1 : function(){ return f1(); }, method2 : function(){ return f2(); } } ; })(); alert(BHX.Singleton.attr1); BHX.Singleton.method1();
이 싱글톤 모드는 모듈 모드라고도 하는데, 관련된 메소드와 속성을 일괄적으로 모듈로 구성하고 네임스페이스를 나누는 역할을 할 수 있다는 의미입니다.
4. 네임스페이스를 분할하기 위해 싱글톤 모드를 사용합니다
1) 전역 선언 수정 방지
/*using a namespace*/ var BHX = {}; BHX.Singleton = { attr1: true , attr2: 10 , method1 : function(){ alert('我是方法1'); }, method2 : function(){ alert('我是方法2'); } }; BHX.Singleton.attr1; var attr1 = false;
이렇게 하면 동일한 변수를 외부에 선언하더라도 attr1이 어느 정도 수정되는 것을 방지할 수 있습니다.
2) 기타 소스코드 수정 방지
요즘 웹페이지의 JavaScript 코드는 라이브러리 코드, 광고 코드, 배지 코드 등 두 개 이상의 소스를 사용하는 경우가 많습니다. 자신의 코드와의 충돌을 피하기 위해 자신의 코드를 모두 포함하는 개체를 정의할 수 있습니다.
var XGP = {}; XGP.Common = { //A singleton with common methods used by all objects and modules } XGP.ErrorCodes = { //An object literal used to store data } XGP.PageHandler = { //A singleton with page specific methods and attributes. }
3) 특수코드 패키징으로 사용
웹페이지가 많은 웹사이트에서는 일부 코드가 모든 웹페이지에서 사용되며 일반적으로 별도의 파일에 저장되지만 일부 코드는 특정 웹페이지에만 사용되며 다른 곳에서는 사용되지 않습니다. 두 가지 유형의 코드를 자체 싱글톤 개체로 래핑하는 것이 가장 좋습니다.
우리는 양식에 기능을 추가하기 위해 Javascript를 자주 사용합니다. 원활한 성능 저하를 위해 먼저 Javascript에 의존하지 않고 일반적인 제출 메커니즘을 사용하여 작업을 완료하는 순수 HTML 페이지를 만드는 것이 일반적입니다.
XGP.RegPage = { FORM_ID: 'reg-form', OUTPUT_ID: 'reg-result', handleSubmit: function(e){ e.preventDefault(); //stop the normal form submission var data = {}; var inputs = XGP.RegPage.formEl.getElementByTagName('input'); for(var i=0, len=inputs.length; i<len; i++){ data[inputs[i].name] = inputs[i].value; } XGP.RegPage.sendRegistration(data); }, sendRegistration: function(data){ //make an xhr request and call displayResult() when response is recieved ... }, displayResult: function(response){ XGP.RegPage.outputEl.innerHTML = response; }, init: function(){ XGP.RegPage.formEl =$(XGP.RegPage.Form_ID); XGP.RegPage.outputEl = $(XGP.RegPage.OUTPUT_ID); //hijack the form submission addEvent(XGP.RegPage.formEl, 'submit', XGP.RegPage.handleSubmit); } } //invoke initialization method after the page load addLoadEvent(XGP.RegPage.init);
5. 게으른 싱글톤
앞서 언급한 싱글톤 패턴에는 또 다른 공통점이 있습니다. 스크립트가 로드될 때 싱글톤 개체가 생성된다는 것입니다. 리소스 집약적이거나 구성 비용이 많이 드는 싱글톤의 경우 인스턴스화를 사용해야 할 때까지 연기하는 것이 더 합리적입니다.
이 기술은 지연 로딩입니다.
구현 단계는 다음과 같습니다.
1) 모든 코드를 생성자 메서드로 이동합니다
2) 호출 타이밍에 대한 전체 제어(정확히 getInstance의 기능)
XGP.lazyLoading = (function(){ var uniqInstance; function constructor(){ var attr = false; function method(){ } return { attrp: true, methodp: function(){ } } } return { getInstance: function(){ if(!uniqInstance){ uniqInstance = constructor(); } return uniqInstance; } } })();
6. 브랜치 기술
분기는 런타임에 설정되는 동적 메서드에서 브라우저 간의 차이점을 캡슐화하는 데 사용되는 기술입니다.
// 分支单例 (判断程序的分支 <浏览器差异的检测>) var Ext = {} ; var def = false ; Ext.More = (function(){ var objA = { // 火狐浏览器 内部的一些配置 attr1:'FF属性1' // 属性1 // 属性2 // 方法1 // 方法2 } ; var objB = { // IE浏览器 内部的一些配置 attr1:'IE属性1' // 属性1 // 属性2 // 方法1 // 方法2 } ; return (def) ?objA:objB; })(); alert(Ext.More.attr1);
예를 들어 웹사이트에서 xhr을 자주 사용하는 경우 호출할 때마다 브라우저 스니핑 코드를 다시 실행해야 하므로 매우 비효율적입니다. 스크립트가 로드될 때 브라우저별 코드를 한 번 식별하는 것이 더 효율적입니다. 이것이 바로 분기 기술이 수행하는 작업입니다. 물론, 분기 기술이 항상 더 효율적인 선택은 아닙니다. 두 개 이상의 분기 중 하나만 사용되고 다른 분기는 메모리를 차지합니다.
분기 기술을 사용할지 여부를 고려할 때 시간 단축과 더 많은 메모리를 차지하는 것에 대한 장단점을 고려해야 합니다.
다음은 분기 기술을 사용하여 XHR을 구현합니다.
var XHR = (function(){ var standard = { createXhrObj: function(){ return new XMLHttpRequest(); } }; var activeXNew = { createXhrObj: function(){ return new ActiveXObject('Msxml2.XMLHTTP'); } }; var activeXOld = { createXhrObj: function(){ return new ActiveXObject('Microsoft.XMLHTTP'); } }; var testObj; try{ testObj = standard.createXhrObj(); return testObj; }catch(e){ try{ testObj = activeXNew.createXhrObj(); return testObj; }catch(e){ try{ testObj = activeXOld.createXhrObj(); return testObj; }catch(e){ throw new Error('No XHR object found in this environment.'); } } } })();
7. 싱글턴 모델의 단점
이제 싱글톤에 대해 많이 알았으니 단점을 살펴보겠습니다.
싱글턴 패턴은 단일 액세스 지점을 제공하므로 모듈 간의 강력한 결합으로 이어질 수 있습니다. 따라서 단위 테스트에 도움이 되지 않습니다.
요약하자면, 싱글톤은 여전히 네임스페이스 정의 및 분기 방법 구현용으로 예약되어 있습니다.
7가지 측면에서 싱글턴 패턴을 소개하면서 싱글턴 패턴에 대해 더 깊이 이해하셨나요? 이 글이 도움이 되었으면 좋겠습니다.