當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
JS之设计模式
文章目錄
- JS之設計模式
- 工廠模式
- 單例模式
- 觀察者模式
- 模板模式
- 適配器模式
- 代理模式
JS之設計模式
## 軟件開發設計流程 需求----分析----設計-----編碼----測試----部署----運維## 開發方式 ### 瀑布式(假設需求沒有變化,不會重復) 需求----分析----設計-----編碼----測試----部署----運維 ### 迭代式(敏捷) 沒有需求或需求完全不明確 不斷迭代下面的階段,需求在不斷變化 需求----分析----設計-----編碼----測試 導致代碼量不斷增長----重復的代碼-----代碼很亂---效率不高-----重構### 重構 采用設計模式方式重構代碼,將冗余的代碼精簡化### 做項目,做產品 項目------只需要完成功能 產品------代碼很規范,盡量做到最好,最優## 什么是設計模式? 設計模式---軟件開發過程中總結出來最好的代碼范式(需要特定場景)問題-----紅燒魚塊?解決辦法:----媽媽說了步驟----比較冗余----百度搜索制作步驟----精練----最簡最優 23種設計模式---只需知道常用 單例------問題----只需要有一個實例解決辦法:-----根據經驗寫---比較冗余-----根據單例范式寫----最簡最優設計模式---抽象---不好理解工廠模式
//工廠模式 //問題:需要根據配置文件自動實例化很多對象 //解決:采用工廠模式 function personFactory(name, age, sex) {//定義工廠factory,用來創建對象var obj = new Object(); //定義一個空對象obj.name = name;obj.age = age;obj.sex = sex;obj.showName = function(){//給對象添加方法return this.name;}return obj; //返回對象 } //工廠生成對象 var p1 = personFactory("張三","22","男"); var p2 = personFactory("李四","23","男"); console.log(p1.showName()) console.log(p1.constructor)//輸出類型---object //缺點:js里面不清楚p1,p2的構造函數,即不清楚是由哪個函數構造//構造函數模式 //問題:需要根據配置文件自動實例化很多對象, 如系統啟動需要實例很多對象 //解決:采用工廠模式 function PersonFactory(name, age, sex) {function Person(name, age, sex) {this.name = name;this.age = age;this.sex = sex;this.showName = function(){return this.name;}// return this;}var p = new Person(name, age, sex);return p; }var p1 = PersonFactory("張三","22","男"); var p2 = PersonFactory("李四","23","男"); console.log(p1.showName()) console.log(p1.constructor) //默認指向自己的構造函數Person //優點:可以知道實例對象的構造函數單例模式
//單例(單一的實例) //在系統中只能有且只有一個實例, 如資源管理器 //前端如何使用? 如頁面上需要多個彈框,需要限制只能有一個(應用場景)<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>單例應用</title> </head> <body><button id="btn">打開彈框</button><script>//創建一個div// var createWindow = function(){// var div = document.createElement("div");//在內存中生成一個div// div.innerHTML = "我是彈框,彈框應該唯一"; //給div加內容// div.style.display = "none"; //默認隱藏// document.body.appendChild(div);//把div寫入頁面// return div;// }// btn.onclick = function(){// var win = createWindow(); //創建彈框// win.style.display = "block"; //顯示彈框// }//缺點:每一次createWindow()都會在內存中生成一個div副本,沒有必要//可以使用單例思想重構//使用單例模式重構var createWindow = (function(){var div;return function(){ //閉包===函數+外部局部變量(緩存)if (!div) { //若div不存在則創建,否則直接返回div = document.createElement("div");//在內存中生成一個divdiv.innerHTML = "我是彈框,彈框應該唯一"; //給div加內容div.style.display = "none"; //默認隱藏document.body.appendChild(div);//把div寫入頁面}return div;}})(); //()表示執行btn.onclick = function(){var win = createWindow(); //創建彈框 //等價于29的functionwin.style.display = "block"; //顯示彈框}</script> </body> </html>觀察者模式
//觀察者---發布訂閱 //場景----買飯(跟服務員說----買XXX飯----服務員下單(訂閱)-----服務員通知(發布)-----) //觀察者----服務員 //被觀察者-----訂單var releaseObj = {}; //發布者 觀察者 releaseObj.list = []; //訂單列表 //添加訂單行為 releaseObj.listen = function(fn) { //fn----訂單releaseObj.list.push(fn);//把訂單存入訂單列表 } //客戶通知服務員下單----添加到list列表里面 releaseObj.listen(function(name, price){ //訂單//若時間太長,取消訂單(直接把list中的函數去掉)console.log("紅燒肉飯訂單:name:", name, ",price:", price, this.list); }) //等待-----玩手機-----等待服務員的通知 releaseObj.notify = function(){ //通知訂單okfor(var i=0, fn; fn=this.list[i++];) {//var i=0; i<xxx; i++//arguments---會接收所有實參 //執行函數 call----參數,參數 apply---[參數,參數]//fn.apply---表示執行fn//fn(this, arguments) fn---function(name, price)//目的:執行fn 保證fn在this作用域里,將所有實參傳入fnfn.apply(this, arguments); //this---releaseObj arguments---參數// fn.call(this, "紅燒肉飯", "20");} } releaseObj.notify("紅燒肉飯", "20"); //通知飯已Ok模板模式
模板----模具----已經存的一種框架,實物,電子檔餅干----模具定義一個抽象的對象(bike),有一個固定的方法(如滾動)----根據這個抽象對象去實現子類(捷安特)----也須實現抽象方法(如滾動) //模板模式----用于構建統一的對象----所有對象擁有統一的行為 //定義抽象自行車----不存在----約定 //老曹----繼承財產-----把國籍轉為中國 //約定----要創建一子類bike實現必須實現wheel方法和hdrive方法 var Bike = function(){ //模板對象 } //空對象 Bike.prototype.wheel = function(){ //空對象定義輪子throw new Error("抽象輪子方法"); } Bike.prototype.hdrive = function(){ //空對象定義動力系統throw new Error("抽象動力系統");//避免子類不實現該方法,直接調用報錯 } // 不能這樣寫 因為調方法就直接報錯 // var bike = new Bike(); // bike.hdrive()//電動車模板 var EBike = function(){} EBike.prototype.wheel = function(){ //空對象定義輪子throw new Error("抽象輪子方法"); } EBike.prototype.edrive = function(){ //空對象定義動力系統throw new Error("抽象動力系統");//避免子類不實現該方法,直接調用報錯 }//根據模板 造子類捷安特 var JATBike = function(){Bike.call(this); //把bike的屬性拷貝過來 } JATBike.prototype = new Bike(); JATBike.prototype.wheel = function(){//業務邏輯console.log("捷安特輪子"); } JATBike.prototype.hdrive = function(){//業務邏輯console.log("人力驅動"); } var jatBike = new JATBike(); jatBike.hdrive();//根據電動車模板---造子類雅迪 var YdBike = function(){EBike.call(this); } YdBike.prototype = new EBike(); YdBike.prototype.wheel = function(){//業務邏輯console.log("捷安特輪子"); } YdBike.prototype.edrive = function(){//業務邏輯console.log("電力驅動"); }適配器模式
適配器---手機充電---需要2孔電腦充電---需要3孔----買插座----墻上2孔插座---2孔----3孔問題:有了自行車,電動車----自行車太累了,電動車買不起-----改裝自行車用二手電動車馬達 /adapter----適配器-----源碼 //改裝自行車 var BikeAdapter = function(engine){Bike.call(this);this.engine = engine; //馬達 } BikeAdapter.prototype = new Bike(); BikeAdapter.prototype.wheel = function(){//業務邏輯console.log("捷安特輪子"); } BikeAdapter.prototype.hdrive = function(){//業務邏輯console.log("馬達驅動", this.engine.edrive()); //不再需要人力驅動 }var ydBike = new YdBike(); var bikeAdapter = new BikeAdapter(ydBike); bikeAdapter.hdrive(); //改裝后的自行車代理模式
代理----設計模式別人代理你的行為,如明星---經理人----行為必須一致,經理人行事必須是按明星要求來webpack--proxy(代理)---將請求--直接過不去--需要代理轉發 //代理---代理對象要與被代理對象有相同行為 //男----送禮物-----委托代理送 var girl = function(name) {this.name = name; } var boy = function(girl) {this.girl = girl;//送禮物this.sendGift = function(gift) {//業務邏輯console.log("hi "+girl.name+ ", 有一個男孩送你禮物:"+gift);} } //代理對象---具備了送禮物能力 var proxyObj = function(girl) {this.girl = girl;//送禮物this.sendGift2 = function(gift) {//new實例化boy對象//var boy = new boy(this.girl);//boy.sendGift(gift);(new boy(this.girl)).sendGift(gift); //送禮物 用了男孩子的方法} } //調用過程----只知道是代理對象所為 var proxy = new proxyObj(new girl("小花")); proxy.sendGift2("99朵玫瑰");例子:前端加載圖片(真實圖片–很大, 等待圖片—很小—代理)
請看proxy.html (見下)
總結
- 上一篇: JS-跨域及其处理
- 下一篇: JavaScript预解析、作用域题目记