建立型設計模式
一、簡單工廠模式:
又叫靜態工廠方法,由一個工廠對象決定建立某一種產品對象類的實例,主要用來建立同一類對象。
不少剛剛瞭解面向對象以後會有不少盲區,例如一個關於登陸表單驗證的例子:javascript
處理前:java
// 用戶名校驗 var LoginAlert = function (text) { this.content = text; }; LoginAlert.prototype.show = function () { // 顯示警示框 }; var userNameAlert = new LoginAlert('用戶名不能多於16個字母或數字'); userNameAlert.show(); // 密碼校驗 var passwordAlert = new LoginAlert('輸入密碼不正確'); passwordAlert.show(); // 添加註冊按鈕 var loginConfirm = function (text) { this.content = text; }; loginConfirm.prototype.show = function () { // 顯示確認框 }; var loginFailConfirm = new loginConfirm('您的用戶名不存在,請從新輸入!'); loginFailConfirm.show(); // 友好自定義提示框 var LoginPrompt = function (text) { this.content = text; }; LoginPrompt.prototype.show = function () { // 顯示提示框 };
處理後:編程
function createPop (type, text) { // 建立一個對象,並對對象拓展屬性和方法 var o = new Object(); o.content = text; o.show = function () {}; if (type === 'alert') { // 警示框差別部分 } if (type === 'prompt') { // 警示框差別部分 } if (type === 'confirm') { // 警示框差別部分 } // 將對象返回 return o; }; var userNameAlert = createPop('alert', '用戶名不能多於16個字母或數字');
團隊項目開發不一樣於我的開發,其對全局變量的限制很大,因此咱們要儘可能少建立全局變量。對於同一類對象在不一樣需求中的重複性使用,不少
時候不須要重複建立,代碼複用是面向對象編程的一條準則。經過對簡單工廠來建立一些對象,可讓這些對象公用一些資源而又私有一些資源
,這是一種很不錯的實踐。不過對於簡單工廠模式,它的使用場合一般也就限制在建立單一對象。設計模式
二、工廠方法模式:
經過對產品類的抽象使其建立業務主要負責用於建立多類產品的實例數組
處理前:緩存
// 建立Java學科類 var Java = function (content) { // 將內容保存在content裏面 以備後日使用 this.content = content; // 建立對象時,經過閉包直接執行,將內容按需求的樣式插入到頁面內 (function (content) { var div = document.createElement('div'); div.innerHTML = content; div.style.color = 'green'; document.getElementById('container').appendChild(div); })(content); }; // 建立PHP學科類 var Php = function (content) { // 將內容保存在content裏面 以備後日使用 this.content = content; // 建立對象時,經過閉包直接執行,將內容按需求的樣式插入到頁面內 (function (content) { var div = document.createElement('div'); div.innerHTML = content; div.style.color = 'yellow'; div.style.background = 'red'; document.getElementById('container').appendChild(div); })(content); }; // 建立Javascript學科類 var JavaScript = function (content) { // 將內容保存在content裏面 以備後日使用 this.content = content; // 建立對象時,經過閉包直接執行,將內容按需求的樣式插入到頁面內 ( function (content) { var div = document.createElement('div'); div.innerHTML = content; div.style.background = 'pink'; document.getElementById('container').appendChild(div); })(content); }; // 學科類工廠 function JobFactory (type, content) { switch (type) { case 'Java': return new Java(content); case 'Php': return new Php(content); case 'Javascript': return new JavaScript(content); }; }
處理後:安全
// 安全模式建立工廠類 var Factory = function (type, content) { if (this instanceof Factory) { var s = new this[type](content); return s; } else { return new Factory(type, content); } }; // 工廠原型中設置建立全部類型數據對象的基類 Factory.prototype = { Java: function (content) { //..... }, Php: function (content) { //..... }, JavaScript: function (content) { //..... }, UI: function (content) { // 將內容保存在content裏面 以備後日使用 this.content = content; // 建立對象時,經過閉包直接執行,將內容按需求的樣式插入到頁面內 (function (content) { var div = document.createElement('div'); div.innerHTML = content; div.style.background = 'pink'; div.style.border = '1px soild red'; document.getElementById('container').appendChild(div); })(content); }, };
對於建立多類對象,前面學過的簡單工廠模式就不太適合了,這是簡單工廠模式的應用侷限,固然這正是工廠方法模式的價值所在,經過工廠方法模式
咱們能夠輕鬆建立多個類的實例對象,這樣工廠方法對象在建立對象的方式也避免了使用者與對象之間的耦合,用戶沒必要關心建立該對象的具體類,只
須要調用工廠方法便可。閉包
三、抽象工廠模式:
經過對類的工廠抽象使其業務用於對產品類的建立,而不負責建立某一類產品的實例。app
舉例:ide
// 汽車抽象類,當使用其實例對象的方法時會拋出錯誤 var Car = function () {}; Car.prototype = { getPrice: function () { return new Error('抽象方法不能調用'); }, getSpeed: function () { return new Error('抽象方法不能調用'); } };
咱們看到咱們建立的這個car類其實什麼都作不了,建立時沒有任何屬性,然而原型prototype上的方法也不能使用,不然會報錯。但在繼承上倒是很是
有用,由於定義了一種類而且定義了該類所必備的方法,若是在子類中沒有重寫這些方法,那麼當調用的時候就會報錯,這一特色是很必要的,由於在一
些大型應用中,總會有一些子類去繼承另外一些父類,這些父類常常會定義一些必要的方法,卻沒有具體的實現,如car類中的 getPrice()和getSpeed()
方法,那麼一旦子類建立了一對象,該對象老是應該具有一些方法的,若是這些方法從父類繼承過來就沒有具體的實現,那麼實例化對象便會調用父類中
的這些方法,若是父類能有一個好的提示,那麼對於忘記重寫子類的這些錯誤遺漏的避免是頗有幫助的,這也是抽象類的一個做用,即定義一個產品蔟,
並聲明一些方法,若是子類中沒有重寫就會拋出錯誤。
// 抽象方法 var VehicleFactory = function (subType, superType) { // 判斷抽象工廠中是否有該抽象類 if (typeof VehicleFactory[superType] === 'function') { // 緩存類 function F () {}; // 繼承父類屬性和方法 F.prototype = new VehicleFactory[superType](); // 將子類constructor指向子類 subType.constructor = subType; // 子類原型繼承父類 subType.prototype = new F(); } else { // 不存在該抽象類拋出錯誤 throw new Error('未建立該抽象類'); } }; // 小汽車抽象類 VehicleFactory.Car = function () { this.type = 'car'; }; VehicleFactory.Car.prototype = { getPrice: function () { return new Error('抽象方法不能調用'); }, getSpeed: function () { return new Error('抽象方法不能調用'); } }; // 寶馬汽車子類 var BMW = function (price, speed) { this.price = price; this.speed = speed; }; // 抽象工廠實現對Car抽象類的繼承 VehicleFactory(BMW, 'Car'); BMW.prototype.getPrice = function () { return this.price; }; BMW.prototype.getSpeed = function () { return this.speed; }; // 掉用 var bmw = new BMW(100000, 1000); console.log(bmw.getPrice); // 100000 console.log(bmw.getSpeed); // 1000
抽象工廠模式是設計模式中最抽象的一種,也是建立模式中惟一一種抽象化建立模式,該模式建立出的結果不是一個真實的對象實例,而是一個類簇,它制
定了類的結構,這也是區別於簡單工廠模式建立單一對象,工廠方法模式建立多類對象。固然因爲JavaScript中不支持抽象化建立與虛擬方法,因此致使
這種模式不能像其餘面嚮對象語言中應用的那麼普遍。
四、建立者模式:
將一個複雜對象的構建層與其表示層相互分離,一樣的構建過程可採用不一樣的表示
// 建立一位人類 var Human = function (param) { // 技能 this.skill = param && param.skill || '保密'; // 興趣愛好 this.hobby = param && param.hobby || '保密'; }; // 類人原型方法 Human.prototype = { getSkill: function () { return this.skill; }, getHobby: function () { return this.hobby; } }; // 實例化姓名類 var Named = function (name) { var that = this; // 構造器 // 構造函數解析姓名與名 (function (name, that) { that.wholeName = name; if (name.indexOf(' ') > -1) { that.FirstName = name.slice(0, name.indexOf(' ')); that.seconName = name.sile(name.indexOf(' ')); } })(name, that); }; // 實例化職位類 var Work = function (work) { var that = this; // 構造器 // 構造函數中經過傳入的職位特殊來設置相應職位以及描述 (function (work, that) { switch (work) { case 'code': that.work = '工程師'; that.workDescript = '天天沉醉於編程'; break; case 'UI': case 'UE': that.work = '設計師'; that.workDescript = '設計更似一種藝術'; break; case 'teach': that.work = '教師'; that.workDescript = '分享也是一種快樂'; break; default: that.work = work; that.workDescript = '對不起,咱們還不清楚您所選擇職位的相關描述'; } })(work, that); }; // 更換指望的職位 Work.prototype.changeWork = function (work) { this.work = work; }; // 添加對職位的描述 Work.prototype.changeDescript = function (setence) { this.workDescript = setence; }; var Person = function (name, work) { // 建立應聘者對象 var _preson = new Human(); // 建立應聘者姓名解析對象 _preson.name = new Named(name); // 建立應聘者指望職位 _person.work = new Work(work); // 將建立的應聘者對象返回 return _preson; }; 使用: var person = new Person('xiao ming', 'code'); console.log(person.skill); // 保密 console.log(person.name.FirstName); // xiao console.log(person.work.work); // 工程師 console.log(person.work.workDescript); // 天天在編程中度過 person.work.changeDescript('更改一下職位描述!'); console.log(person.work.workDescript); // 更改一下職位描述
五、原型模式:
用原型實例指向建立對象的類,使用與建立新的對象的類共享原型對象的屬性和方法。
處理前:
// 圖片輪播類 var LoopImages = function (imgArr, container) { this.imagesArray = imgArr; this.container = container; this.createImage = function () {}; this.changeImage = function () {}; }; // 漸隱切換類 var FadeLoopImage = function (imgArr, container, arrow) { LoopImages.call(this, imgArr, container); // 切換箭頭私有變量 this.arrow = arrow; this.changeImage = function () { console.log('FadeLoopImage changeImage function'); }; }; // 實例化一個漸隱切換圖片類 var fadeImg = new FadeLoopImage(['01.jpg', '02.jpg', '03.jpg', '04.jpg'], 'slide', ['left.jpg', 'right.jpg']);
處理後:
// 圖片輪播類 var LoopImage = function (imgArr, container) { this.imagesArray = imgArr; // 輪播圖片數組 this.container = container; // 輪播圖片容器 }; // 漸隱切換類 var FadeLoopImage = function (imgArr, container, arrow) { LoopImages.call(this, imgArr, container); // 切換箭頭私有變量 this.arrow = arrow; }; FadeLoopImage.prototype = new LoopImages(); FadeLoopImage.prototype.changeImage = function () { console.log('FadeLoopImage changeImage function'); }; // 測試用例 console.log(fadeImg.container); // slide fadeImg.changeImage(); // FadeLoopImage changeImage function // 原型繼承 function prototypeExtend () { var F = function () {}; // 緩存類,爲實例化返回對象臨時建立 args = arguments, i = 0, len = args.length; for (; i< lenl i++) { // 遍歷每一個模板對象的屬性 for (var j in args[i]) { // 將這些屬性賦值到緩存類原型中 F.prototype[j] = args[i][j]; } } // 返回緩存類的一個實例 return new F(); }; var penguin = prototypeExtend({ speed: 20, swim: function () { console.log('游泳速度' + this.spee) } },{ run: function () { console.log('奔跑速度' + speed) } },{ jump: function () { console.log('跳躍動做') } }); penguin.swim(); // 游泳速度20 penguin.run(10); // 奔跑速度10 penguin.jumo(); // 跳躍動做
六、單例模式:
又稱爲單體模式,是隻容許實例化一次的對象類,有時咱們也用一個對象來規劃一個命名空間,層次分明的管理對象上的屬性和方法。
案例:
// 惰性載入單例 var LazySingle = (function () { // 單例實例引用 var _instance = null; // 單例 function Single () { // 這裏定義了私有的屬性和方法 return { publicMethod: function () {}, publicProperty: '1.0' }; }; //獲取單例對象接口 return function () { // 若是爲建立單例建立單例 if (!_instance) { _instance = Single(); }; // 返回單例 return _instance; }; })(); 測試用例: console.log(LazySingle().publicProperty); // 1.0
單例模式有時也被稱爲單體模式,它只是一個只容許實例化一次的對象類,有時這麼作也是爲了節省系統資源。固然Javascript中單例模式常常 做爲命名空間對象實現,經過單例對象咱們能夠將各個模塊的代碼層次分明的梳理在一塊兒。