国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

前端設(shè)計(jì)模式

newsning / 714人閱讀

摘要:作為一個(gè)前端新人,學(xué)習(xí)了設(shè)計(jì)模式以后,希望能從源頭上,用淺顯易懂的語言來解釋它。創(chuàng)建型設(shè)計(jì)模式創(chuàng)建型設(shè)計(jì)模式故名思意,這些模式都是用來創(chuàng)建實(shí)例對象的。這就是簡單工廠模式。這就是工廠方法模式。

作為一個(gè)前端新人,學(xué)習(xí)了設(shè)計(jì)模式以后,希望能從源頭上,用淺顯易懂的語言來解釋它。當(dāng)然不一定是正確的,只是我個(gè)人對設(shè)計(jì)模式的一點(diǎn)淺顯理解。
創(chuàng)建型設(shè)計(jì)模式

創(chuàng)建型設(shè)計(jì)模式:故名思意,這些模式都是用來創(chuàng)建實(shí)例對象的。

單例模式

首先我們需要理解什么是單例。
單:指的是一個(gè)。
例:指的是創(chuàng)建的實(shí)例。
單例:指的是創(chuàng)建的總是同一個(gè)實(shí)例。也就是使用類創(chuàng)建的實(shí)例始終是相同的。
我們先看下面的一段代碼:

class Person{
  constructor(){}
}
let p1 = new Person();
let p2 = new Person();
console.log(p1===p2)  //false

上面這段代碼,定義了一個(gè)Person類,通過這個(gè)類創(chuàng)建了兩個(gè)實(shí)例,我們可以看到最終這兩個(gè)實(shí)例是不相等的。也就是說,通過同一個(gè)類得到的實(shí)例不是同一個(gè)(這本就是理所應(yīng)當(dāng)),但是如果我們想始終得到的是同一個(gè)實(shí)例,那么這就是單例模式。那么應(yīng)該如何實(shí)現(xiàn)單例模式了:
想要實(shí)現(xiàn)單例模式,我們需要注意兩點(diǎn):

需要使用return。使用new的時(shí)候如果沒有手動(dòng)設(shè)置return,那么會默認(rèn)返回this。但是,我們這里要使得每次返回的實(shí)例相同,也就是需要手動(dòng)控制創(chuàng)建的對象,因此這里需要使用return

我們需要每次return的是同一個(gè)對象。也就是說實(shí)際上在第一次實(shí)例的時(shí)候,需要把這個(gè)實(shí)例保存起來。再下一個(gè)實(shí)例的時(shí)候,直接return這個(gè)保存的實(shí)例。因此,這里需要用到閉包了

代碼實(shí)現(xiàn)如下:

(function(){
  let instance = null;
  return class{
      constructor(){
        if(!instance){
         //第一次創(chuàng)建實(shí)例,那么需要把實(shí)例保存
          instance = this;
        }else{
          return instance;
      }
  }
  }
})()


let p3= new Person();
let p4 = new Person();
console.log(p3===p4)  //true

從上面的代碼中,我們可以看到在閉包中,使用instance變量來保存創(chuàng)建的實(shí)例,每次返回的都是第一次創(chuàng)建的實(shí)例。這樣的話就實(shí)現(xiàn)了無論創(chuàng)建多少次,創(chuàng)建的都是同一個(gè)實(shí)例,這就是單例模式。

工廠模式

對于工廠來說,我們的印象可能是里面具有各種各樣的模具,根據(jù)你想要的產(chǎn)品的模型,生產(chǎn)你需要的產(chǎn)品。比如說你請工廠幫你加工一個(gè)產(chǎn)品,你只需要告訴工廠你這個(gè)產(chǎn)品的結(jié)構(gòu),工廠就會有對應(yīng)的模型幫你生產(chǎn),你不需要去關(guān)心它具體是怎么加工的。同樣工廠模式也是這樣,(工廠模式也是創(chuàng)建型設(shè)計(jì)模式,用于創(chuàng)建實(shí)例對象的)你不需要自己去找對應(yīng)的類來創(chuàng)建實(shí)例,你只需要告訴工廠類你要?jiǎng)?chuàng)建什么實(shí)例,他就會返回你需要的實(shí)例對象。
工廠模式根據(jù)抽象程度的不同,分為三種:

簡單工廠模式

工廠方法模式

抽象工廠模式

簡單工廠模式
定義:定義一個(gè)工廠類,通過工廠函數(shù),根據(jù)傳入的參數(shù)不同,返回不同的實(shí)例。看下面的代碼:

//學(xué)生類
class Student{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name)
  }
}

//老師類
class Teacher{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name)
  }
}

//警察類
class Policeman{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name)
  }
}
根據(jù)類創(chuàng)建對象
const s1 = new Student("王小一",24);
const t1 = new Teacher("李一老師",39);
const p1= new Policeman("張一警官",40);

我們可以看到,上面代碼中定義了三個(gè)類,學(xué)生類,老師類和警察類。而且它們具有相同的屬性和方法。當(dāng)我們需要?jiǎng)?chuàng)建學(xué)生實(shí)例時(shí),我們調(diào)用學(xué)生類。當(dāng)我們需要?jiǎng)?chuàng)建老師實(shí)例時(shí),我們調(diào)用老師類,當(dāng)我們需要?jiǎng)?chuàng)建警察實(shí)例,我們調(diào)用警察類。假設(shè)我們有更多的人物類,它們具有相同的功能,那么當(dāng)我們需要?jiǎng)?chuàng)建實(shí)例的時(shí)候,我們同樣需要調(diào)用相對應(yīng)的類。事實(shí)上,這些類實(shí)現(xiàn)的都是相同的功能,那么我們可不可以把所有的創(chuàng)建這些人物實(shí)例都通過一個(gè)類來實(shí)現(xiàn)了。我們嘗試將代碼修改為如下:

//學(xué)生類
class Student{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name)
  }
}

//老師類
class Teacher{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name)
  }
}

//警察類
class Policeman{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  showName(){
    console.log(this.name)
  }
}

//工廠類
class Factory{
  let obj = null;
  //工廠函數(shù)
  constructor(role,name,age){
    switch(role){
      case "student":
         obj = new Student(name,age);
         break;
     case "teacher":
         obj = new Teacher(name,age);
         break;
     case "policeman":
         obj = new Policeman(name,age);
         break;
    }
  }
 return obj;
}

const s2 = new Factory("student","王小二",25);
const t2 = new Factory("teacher","李二老師",39);
const p2 = new Factory("policeman","張二警官",40);

從上面的代碼中,我們可以看到我們同樣定義了學(xué)生類,老師類,警察類這三個(gè)類,但是我們創(chuàng)建實(shí)例時(shí)通過Factory這個(gè)類,不再通過相對應(yīng)的人物類了。這個(gè)Factory類就是工廠類,我們觀察工廠類的實(shí)現(xiàn),發(fā)現(xiàn)里面是一個(gè)工廠函數(shù)(這里直接使用了constructor,也可以自己定義工廠函數(shù)),通過傳遞給工廠函數(shù)的參數(shù)不同,返回不同的實(shí)例。這就是簡單工廠模式。

簡單工廠模式總結(jié)
實(shí)現(xiàn):從上面的代碼中我們可以知道,所謂簡單工廠模式就是一個(gè)工廠類和一個(gè)工廠函數(shù),通過傳入?yún)?shù)的不同,返回不同的實(shí)例。
特點(diǎn):1. 需要?jiǎng)?chuàng)建的類較少,因?yàn)樾枰鶕?jù)傳入的參數(shù)來判斷返回的實(shí)例,如果類太多,那么就會導(dǎo)致邏輯復(fù)雜。2. 不需要關(guān)注實(shí)例的創(chuàng)建過程,只需要傳入相對應(yīng)的值即可。
適用場景:舉一個(gè)生活中實(shí)際的使用場合,假如我們上體育課需要去拿籃球,足球和排球,我們可以自己去一個(gè)一個(gè)找對應(yīng)的球(類似于上面通過自己來創(chuàng)建對象),也可以通過管理員,告訴管理員需要什么樣的球,至于管理員是怎么找到這個(gè)相對應(yīng)的球,就與我們不相關(guān)了。這個(gè)管理員就是工廠類。
缺點(diǎn):從簡單工廠模式的特點(diǎn)中我們可以知道,簡單工廠模式適合于創(chuàng)建的類較少,一旦需要的類較多,邏輯就會復(fù)雜。而且一旦需要添加新的類,就得重新修改工廠類,這樣顯得非常不方便。

工廠方法模式
工廠方法模式是對簡單工廠的進(jìn)一步優(yōu)化, 在工廠方法模式中,我們不再提供一個(gè)統(tǒng)一的工廠類來創(chuàng)建所有的對象,而是針對不同的對象提供不同的工廠。也就是說每個(gè)對象都有一個(gè)與之對應(yīng)的工廠。說的好像挺復(fù)雜,其實(shí)在我看來他就是解決簡單工廠模式存在的不方便添加新的類,因?yàn)樘砑有碌念愐院笮枰薷墓S函數(shù)。而工廠方法模式就是解決這個(gè)問題,看下面的代碼:

let Factory = (function(){
  let s = {
    Student(name,age){
      this.name = name;
      this.age = age;
      return this;
    },
    Teacher(name,age){
      this.name = name;
      this.age = age;
      return this;
    },
    Policeman(name,age){
      this.name = name;
      this.age = age;
      return this;
    },
    //在這里添加新的類
    Doctor(name,age){
      this.name = name;
      this.age = age;
      return this;
    }
  }

  return class {
    //工廠函數(shù)根據(jù)傳進(jìn)來的來的參數(shù)不同而不同。
    constructor(type,name,age){
      if(s.hasOwnProperty(type)){
        return s[type].call(this,name,age)
      }else{
        throw new Error(`不存在${type}類`)
      }

    }
  }


})()

let s3 = new Factory("Student","王小三",25);
let t3 = new Factory("Teacher","李三老師",25);
let p3 = new Factory("Policeman","張三警官",28);
let d3 = new Factory("Doctor","楊醫(yī)生",33);

從上面的代碼中,我們可以看到,相比于簡單工廠函數(shù),工廠方法模式的工廠函數(shù)不是固定的,而是根據(jù)type不同而不同。當(dāng)我們需要添加新的類時(shí),只需要在s對象中添加實(shí)例即可,不需要修改工廠函數(shù)。這樣的話就不會因?yàn)樾枰砑有碌念悾薷倪^多的代碼邏輯。這就是工廠方法模式。其實(shí)就是對簡單工廠模式的優(yōu)化而已。

建造者模式(builder pattern)

提到建造者,我們可能第一印象就是城市中建高樓大廈,建房子一般設(shè)計(jì)到業(yè)主,項(xiàng)目負(fù)責(zé)人,建筑隊(duì)工人。業(yè)主告訴項(xiàng)目負(fù)責(zé)人,需要建造什么樣的房子,項(xiàng)目負(fù)責(zé)人告訴工人應(yīng)該怎么修建,不同工人完成不同工作。大家各司其職,最終得到一個(gè)建成的房子。雖然在建房子過程中,各個(gè)部分都需要打交道,但是更多的還是各司其職,每個(gè)人完成每個(gè)人的工作。其實(shí)就是把一個(gè)復(fù)雜的建房子工程,拆分成了若干部分由不同人來完成。在編程中也是如此,如果我們需要?jiǎng)?chuàng)建一個(gè)復(fù)雜的對象,可以把這個(gè)對象進(jìn)行構(gòu)建,使得不同部分,完成不同功能。
建造者模式定義:將一個(gè)復(fù)雜的對象分解成多個(gè)簡單的對象來進(jìn)行構(gòu)建,將復(fù)雜的構(gòu)建層與表示層分離,使得相同的構(gòu)建過程可以創(chuàng)建不同的表示的模式便是建造者模式。看定義通常是無法直接理解這種設(shè)計(jì)模式的,還是直接看代碼:
假設(shè)我們需要?jiǎng)?chuàng)建一輛車,車的組件包括車名,車牌號,車的價(jià)錢,車的引擎等。我們先看不使用建造者模式應(yīng)該如何創(chuàng)建:

class Car{
  constructor(){
    this.name = "";
    this.number = "";
    this.price = "";
    this.engine = "";
  }
//設(shè)置名字
  setName(){
    this.name = "寶馬";
  }
//設(shè)置車牌號
  setNumber(){
    this.number = "888888"
  }
//設(shè)置價(jià)錢
  setPrice(){
    this.price = "100萬"
  }
//設(shè)置引擎
  setEngine(){
    this.engine = "最好的引擎"
  }
//車的創(chuàng)建
  getCar(){
    this.setName();
    this.setNumber();
    this.setPrice();
    this.setEngine();
  }
}

//創(chuàng)建一個(gè)車:
let car = new Car();
car.getCar();
console.log(car)

從上面的代碼中,我們可以看到創(chuàng)建一輛車需要的元素包括:name,number,price,engine。每一種元素又需要setxx來多帶帶實(shí)現(xiàn),最終車的創(chuàng)建還需要通過getCar來完成。也就是說在創(chuàng)建車的過程中需要的元素較多,創(chuàng)建過程相互影響,相互耦合。這只是簡單的4個(gè)元素,而且耦合性也不是太高,但是假設(shè)元素他特別多,代碼的耦合性也特別多,如果出現(xiàn)添加新的要素,那么實(shí)現(xiàn)起來要修改的代碼就太多了。因此,我們需要對代碼進(jìn)行解耦,這就是建造者模式。
上面我們提到了建造一個(gè)房子,需要業(yè)主,項(xiàng)目負(fù)責(zé)人,建筑工人。其實(shí)建造者模式也包括這三個(gè)類:產(chǎn)品類(客戶提出產(chǎn)品需要),指揮者類,建造者類。
建造者模式的使用流程如下:

客戶提出產(chǎn)品需求:比如上面產(chǎn)品就是一輛小汽車,產(chǎn)品要素包括name,number,price,engine

指揮者根據(jù)產(chǎn)品需求,安排建造者完成需求的各個(gè)部分

建造者完成相應(yīng)的部分

使用建造者模式修改上面的代碼如下:

//產(chǎn)品類:產(chǎn)品要素
class Car{
  constructor(){
    this.name = "";
    this.number = "";
    this.price = "";
    this.engine = "";
  }
}


//建造者類:各種工人完成相應(yīng)的部分
class CarBuilder{
  setName(){
    this.name = "寶馬";
  }
  setNumber(){
    this.number = "888888";
  }
  setPrice(price){
    this.price = "100萬";
  }
  setEngine(engine){
    this.engine = "最好的引擎";
  }
  getCar(){
    var car = new Car();
    car.name = this.name;
    car.number = this.number;
    car.price = this.price;
    car.engine = this.engine;
    return car;
  }
}

//指揮官類:指揮工人完成各部分工作
class Director{
  action(builder){
    builder.setName();
    builder.setNumber();
    builder.setPrice();
    builder.setEngine();
  }
}

//使用方法:

let builder = new CarBuilder();
let director = new Director();
director.action(builder);
let car = builder.getCar();
console.log(car)

從上面的代碼中,我們可以看出,定義了產(chǎn)品類,主要負(fù)責(zé)定義產(chǎn)品的需求;建造者類,主要負(fù)責(zé)完成需求的各個(gè)部分;指揮者類,主要負(fù)責(zé)指揮工人完成各部分工作。實(shí)際上就是把一輛車的復(fù)雜的創(chuàng)建過程抽離成三個(gè)簡單的類來完成,大家各司其職,減少了代碼的耦合。當(dāng)以后需要添加新的需求時(shí),只需要在各個(gè)部分多帶帶定義即可,比如現(xiàn)在造汽車還需要安裝玻璃,那么只需要在每個(gè)類里面定義玻璃相關(guān)的要素,建造者,指揮者即可。而不需要考慮代碼的各部分耦合。這就是建造者模式。

原型模式

原型模式:通俗點(diǎn)講就是創(chuàng)建一個(gè)共享的原型,并通過拷貝這些原型創(chuàng)建新的對象。在我看來,其實(shí)原型模式就是指定新創(chuàng)建對象的模型,更通俗一點(diǎn)來說就是我想要新創(chuàng)建的對象的原型是我指定的對象。最簡單的原型模式的實(shí)現(xiàn)就是通過Object.create()。Object.create(),會使用現(xiàn)有的對象來提供新創(chuàng)建的對象的__proto__。

let person = {
 name:"hello",
 age:24
}

let anotherPerson = Object.create(person);
console.log(anotherPerson.__proto__)  //{name: "hello", age: 24}

anotherPerson.name = "world";  //可以修改屬性
anotherPerson.job = "teacher";

上面的代碼使用Object.create()將person對象作為anotherPerson對象的原型,創(chuàng)建了anotherPerson。因此anotherPerson可以直接獲得person的屬性name,age等。

另外,如果我們想要自己實(shí)現(xiàn)原型模式,而不是使用封裝好的Object.create()函數(shù),那么可以使用原型繼承來實(shí)現(xiàn):

function F(){

}

F.prototype.g = function(){}


//G類繼承F類

function G(){
  F.call(this);
}

//原型繼承
function Fn(){}
Fn.prototype = F.prototype;
G.prototype = new Fn();



G.prototype.constructor = G;

上面的代碼,學(xué)過js的應(yīng)該都能看懂,沒什么好解釋的。
原型模式總結(jié):
原型模式就是創(chuàng)建一個(gè)指定原型的對象。如果我們需要重復(fù)創(chuàng)建某個(gè)對象,那么就可以使用原型模式來實(shí)現(xiàn)。

結(jié)構(gòu)性設(shè)計(jì)模式

上面的創(chuàng)建型設(shè)計(jì)模式,專注于創(chuàng)建對象。而結(jié)構(gòu)性設(shè)計(jì)模式則專注于結(jié)構(gòu)設(shè)計(jì),通俗點(diǎn)來說就是對象與對象之間的結(jié)構(gòu)設(shè)計(jì),也就是如何將類或者對象進(jìn)行更好的組織,以方便使用。

外觀設(shè)計(jì)模式

外觀設(shè)計(jì)模式定義:為一組復(fù)雜的子接口提供一個(gè)更高級的統(tǒng)一接口,以便更方便的去實(shí)現(xiàn)子接口的功能。看定義總是感覺很復(fù)雜,我們根據(jù)一些場景來具體分析:

HTML代碼
 
按鈕1
按鈕2
js代碼 let oBtn1= document.getElementById("btn1"); let oBtn2= document.getElementById("btn2"); //按鈕1 function btn1Fn(){ console.log("這里是按鈕1的內(nèi)容") } //DOM事件的兼容性處理 if( document.addEventListener ){ oBtn1.addEventListener("click" , btn1Fn, false); }else if(document.attachEvent){ oBtn1.attachEvent("onclick" , btn1Fn); }else{ oBtn1.onclick = btn1Fn; } //按鈕2 function btn2Fn(){ console.log("這里是按鈕2的內(nèi)容") } //DOM事件的兼容性處理 if( document.addEventListener ){ oBtn1.addEventListener("click" , btn2Fn, false); }else if(document.attachEvent){ oBtn1.attachEvent("onclick" , btn2Fn); }else{ oBtn1.onclick = btn2Fn; }

上面代碼中由兩個(gè)按鈕,每個(gè)按鈕有對應(yīng)的點(diǎn)擊事件。但是我們知道如果直接使用onclickDOM0級點(diǎn)擊事件,那么就可能出現(xiàn)后續(xù)的事件覆蓋前面的。因此建議使用DOM2級點(diǎn)擊事件,但是addEventListener存在兼容性問題,在IE中存在不兼容。因此我們需要對每次事件做兼容性處理。從上面的代碼中,我們可以看出,我們對按鈕1和按鈕2都做了兼容性處理。事實(shí)上,這些兼容性處理都是相同的,如果每一次都去寫復(fù)雜的重復(fù)的兼容性代碼,是沒有意義的。因此,我們通常會將兼容性處理封裝起來,作為一個(gè)統(tǒng)一的接口,在需要的時(shí)候,直接調(diào)用這個(gè)接口,而不是再去重復(fù)寫這個(gè)復(fù)雜的兼容代碼,這種將復(fù)雜的代碼封裝起來,其實(shí)就是外觀設(shè)計(jì)模式.我們看使用外觀設(shè)計(jì)模式實(shí)現(xiàn)的代碼:

let oBtn1= document.getElementById("btn1");
let oBtn2= document.getElementById("btn2");

//按鈕1
function btn1Fn(){
  console.log("這里是按鈕1的內(nèi)容")
}
//按鈕2
function btn2Fn(){
  console.log("這里是按鈕2的內(nèi)容")
}

function bindEvent(element,type,fn) {
  if(document.addEventListener){
    element.addEventListener(type,fn,false)
  }else if(document.attachEvent){
    element.attachEvent("on"+type,fn)
  }else{
    element["on"+type] = fn;
  }
}
bindEvent(oBtn1,"click",btn1Fn)
bindEvent(oBtn2,"click",btn2Fn)

從上面的代碼中,我們可以看到使用了bindEvent來封裝兼容性處理,然后oBtn1和oBtn2觸發(fā)點(diǎn)擊事件都是直接調(diào)用這個(gè)封裝函數(shù)。其實(shí)這就是外觀模式的一次典型應(yīng)用。所有的API的兼容性封裝其實(shí)都是外觀模式的應(yīng)用。外觀模式其實(shí)就是把一些復(fù)雜的操作隱藏起來,然后我們從更高級別直接調(diào)用。我們再看我們在開發(fā)中經(jīng)常使用到的一個(gè)例子:

var  person = {
  init:function(){
  //  這里是初始化代碼
  },
  getAge:function(){
  //  這里是獲取元素的方法

  },
  getName:function(){
  //  這里是獲取樣式的代碼
  },
  getJob:function(){
  //這里是獲取個(gè)人工作的代碼
  }
}
var name = person.getName();

上面的代碼是一個(gè)對象person,里面封裝了與個(gè)人信息相關(guān)的age,name,job等方法,然后在需要獲取這些信息時(shí),我們使用person.xx來調(diào)用。其實(shí)這就是外觀模式的另外一種應(yīng)用。在開發(fā)中,我們經(jīng)常會使用命名空間,將一些相關(guān)的信息都封裝到這個(gè)對象中,這種將各類操作饑餓和在一起,對外提供統(tǒng)一的接口就是外觀模式的典型應(yīng)用。
外觀設(shè)計(jì)模式總結(jié):外觀設(shè)計(jì)模式時(shí)結(jié)構(gòu)性設(shè)計(jì)模式,我們之前說過結(jié)構(gòu)型設(shè)計(jì)模式是用于組織代碼結(jié)構(gòu)的。而外觀設(shè)計(jì)模式就是把所有的子類饑餓和在一起,對外提供統(tǒng)一的接口這樣的一種組織形式。典型的使用就是各種兼容性API的封裝和命名空間的使用。

適配器設(shè)計(jì)模式

提到適配器,我們想到的可能是電源適配器。一些電子產(chǎn)品的插座是三孔的,但是如果沒有三孔插座,那么我們就需要使用轉(zhuǎn)換器,使用兩孔插座通過轉(zhuǎn)換器來給三孔電子產(chǎn)品充電,這個(gè)轉(zhuǎn)換器就是適配器。在生活中,我們經(jīng)常會碰到這種由于接口不同需要通過轉(zhuǎn)換來實(shí)現(xiàn)的情況,在實(shí)際的代碼開發(fā)中,我們經(jīng)常也會遇到接口不同,需要進(jìn)行轉(zhuǎn)換的過程。這個(gè)轉(zhuǎn)換的過程就是適配。這種設(shè)計(jì)模式就是適配器設(shè)計(jì)模式。
適配器模式定義:將一個(gè)類的接口轉(zhuǎn)換成另外一個(gè)接口,以滿足用戶需求,解決接口不一樣而產(chǎn)生的問題。看具體的代碼:

function getInfo(){
  //假設(shè)result為請求后臺得到的數(shù)據(jù),數(shù)組形式

  var result = ["henry",24,"teacher"];
  console.log("名字是"+result[0]+"年齡是"+result[1]+"職業(yè)是"+result[2])
  
}

上面的代碼中,定義了一個(gè)用于獲取個(gè)人信息的函數(shù),個(gè)人信息的獲取為通過后臺接口返回到result中。現(xiàn)在返回的數(shù)據(jù)為數(shù)組形式。我們后面所有的操作都是按照數(shù)組來進(jìn)行的,比如獲取姓名result[0]。獲取年齡為result[1]。但是,假如后端接口發(fā)生變化了,不再返回?cái)?shù)組形式了(這在實(shí)際的開發(fā)中可能非常常見)。而實(shí)返回一個(gè)對象了。那么我們后面所有的使用數(shù)組的操作就都是錯(cuò)誤的了,這樣的話所有涉及到數(shù)據(jù)的都需要進(jìn)行修改,如果后續(xù)代碼非常多,那么修改起來就非常麻煩了。這時(shí)候,我們可能考慮變通一下,將返回的對象,轉(zhuǎn)換成我們需要的數(shù)組即可。代碼如下:

function fn2(){
  //假設(shè)result2為請求后臺得到的數(shù)據(jù),對象形式

  var result2 = {
    name:"henry",
    age:24,
    job:"teacher"
  }
  //將對象轉(zhuǎn)化成數(shù)組  
  function objToArray(obj){
    var arr = [];
    for(var key in obj){
      arr.push(obj[key])
    }
    return arr;
  }
  var result =  objToArray(result2)


  console.log("名字是"+result[0]+"年齡是"+result[1]+"職業(yè)是"+result[2])

}

上面的代碼中,result2為后臺請求的接口,數(shù)據(jù)類型是對象。但是我們之前都是按照數(shù)組處理的,因此我們需要將對象轉(zhuǎn)換成數(shù)組,函數(shù)objToArray就是用來轉(zhuǎn)換的函數(shù)。這樣的話,我們就不需要去修改后面的代碼,這個(gè)轉(zhuǎn)換的過程就是適配過程。objToArray就是適配函數(shù)。這就是適配器設(shè)計(jì)模式。
適配器設(shè)計(jì)模式總結(jié):適配器設(shè)計(jì)模式其實(shí)就是把一些不適合我們當(dāng)前使用的接口,通過適配以后,轉(zhuǎn)換成能夠被我們使用的接口。最常見的就是接口的轉(zhuǎn)換

代理模式

提到代理,我們可能想到的是代理人。在生活中代理人最多的可能就是明星了,每個(gè)明星都有自己的代理人,我們找明星合作通常都是先接觸代理人,然后才接觸明星。也就是說這個(gè)代理人是在我們和明星之間進(jìn)行了一次攔截,篩選出符合見明星的人。其實(shí)代理模式在開發(fā)中也是這樣,只不過這里代理的是對象,而不是明星,通過為對象提供一個(gè)代理,用來控制對這個(gè)對象的訪問。
代理模式定義:為對象提供一個(gè)代理,用來控制對這個(gè)對象的訪問。
下面以具體代碼舉例:比如公司的個(gè)人信息的訪問:

let person = {
  id = "1",
  name = "劉亦菲",
  age:30
}
console.log(person.name) 

上面定義了一個(gè)包含個(gè)人信息的對象person,如果沒有進(jìn)行代理,那么可以直接通過person.xx進(jìn)行訪問。但是,事實(shí)上我們不希望個(gè)人信息被查看,只有本人能夠進(jìn)行查看和修改。那么這時(shí)候我們可以對對象的訪問添加代理。具體代碼如下:

let info = (function(){
  let person = {
    id:1,
    name:"劉亦菲",
    age:24,
    job:"teacher"
  }

  return function({id}){
    //代理對象
    let handle = {
      get:function(target,key){
        if(key === "age"){
          if(id === 1){
            return Reflect.get(target,key)
          }else{
            throw new Error("您沒有權(quán)限查看該信息")
          }
        }
      },
      set:function(target,key,value){
        if(id === 1){
          return Reflect.set(target,key,value)
        }else{
          throw new Error("您沒有權(quán)限修改個(gè)人信息")
        }
      }
    }
    return new Proxy(person,handle)
  }
})()

let star = info({id:1})
console.log(star.age)
star.age = 30;
console.log(star.age)

通過使用new Proxy(target,handle)來進(jìn)行代理。其中target為被代理對象,handle為代理對象或者說攔截對象。在handle中我們通過定義get和set函數(shù)來進(jìn)行攔截,只有id為1的人才能查看自己的個(gè)人信息。這就是代理模式。
代理模式的應(yīng)用場景:
上面的例子只是簡單的代理對象的訪問,其實(shí)代理更多的時(shí)候是用于控制開銷很大的對象的訪問。比如,一個(gè)創(chuàng)建實(shí)例開銷很大的訪問,它會把創(chuàng)建實(shí)例放到方法被調(diào)用的時(shí)候(也就是真正需要被用到的時(shí)候),因?yàn)槿绻麄€(gè)程序運(yùn)行期間都沒有用到這個(gè)對象,那么就不需要?jiǎng)?chuàng)建它,這樣可以大大節(jié)省資源。比如圖片的延遲加載,我們并不需要一開始就加載所有的圖片,而是使用一張loading圖片來代替它們,只有在真正需要展示這張圖片的時(shí)候,再替代掉src即可。
代理模式的總結(jié):
歸功接底代理模式就是控制對對象的訪問,無論是攔截訪問,還是延遲訪問都是對對象訪問的控制罷了。如果你要訪問一個(gè)對象,但是你不想馬上訪問,或者不想直接訪問那么這都是代理模式。

裝飾者模式

裝飾是生活中很常見的行為,我們給房子搞裝修,自己裝扮自己的臥室等這些都能夠算作裝飾,那么我們?yōu)槭裁匆阊b飾?還不是為了讓房子變得更加美觀,漂亮,更有特色。同樣,在開發(fā)中裝飾者模式也是為了給對象增加新的特性,或者說增加新的功能。
裝飾者模式定義:在不創(chuàng)建新對象的情況下,給對象添加新的特性。就類似于在不破壞房子的情況下,給房子進(jìn)行裝修,我們不可能把買來的房子拆了再重新建一個(gè)再裝修,同樣裝飾者模式是在不創(chuàng)建新對象的情況下,給對象增加新的特性。下面看具體代碼:

 class Car{
    constructor(name,price){
      this.name = name,
      this.price = price
    }
    getCar(){
      console.log("買了這輛車")
    }
  }

  let xiaoming = new Car("寶馬","100萬");
  xiaoming.getCar();
  let xiaohong = new Car("豐田","50萬");
  xiaohong.getCar();
  let xiaogang = new Car("大眾","30萬");
  xiaogang.getCar();

如上面代碼所示:定義了汽車類,小明花了100萬買了寶馬車,小紅花了50萬買了豐田車,小剛花了30萬買了大眾車。但是這時(shí)候經(jīng)銷商突然進(jìn)行促銷了,說買寶馬的可以再送兩個(gè)輪胎,買豐田的可以再送購物卡,買大眾的可以再送加油卡。那么這時(shí)候?qū)τ谛∶鳎偅〖t它們來說應(yīng)該怎么辦了?他們應(yīng)該也有這些送的東西(注意每種車送的東西不一樣),我們不可能再將這些特性再添加到Car類上面去,然后再創(chuàng)建小明等實(shí)例去買車。也就是說我們需要再不創(chuàng)建新的實(shí)例的情況下,給對象添加特性,這恰好是裝飾著模式的定義,下面看具體的代碼實(shí)現(xiàn):

  class Car{
    constructor(name,price){
      this.name = name,
        this.price = price
    }
    getCar(){
      console.log("買了這輛車")
    }
  }

  let xiaoming = new Car("寶馬","100萬");
  xiaoming.getCar();
  let xiaohong = new Car("豐田","50萬");
  xiaohong.getCar();
  let xiaogang = new Car("大眾","30萬");
  xiaogang.getCar();

  
  //裝飾過程
  function decoratorBaoma(){
    this.wheel = "寶馬車送輪胎"
  }
  decoratorBaoma.call(xiaoming)

  function decoratorFengtian(){
    this.shoppingcard = "豐田車送購物卡"
  }
  decoratorFengtian.call(xiaohong)

  function decoratordazhong(){
    this.oil = "大眾車送加油卡"
  }
  decoratordazhong.call(xiaogang)
  console.log(xiaoming)
  console.log(xiaohong)

如面代碼所示:我們在沒有創(chuàng)建新對象的情況下,定義了三個(gè)裝飾函數(shù),通過給寶馬車用戶添加wheel屬性送輪胎,給豐田車用戶添加shoppingcard屬性送購物卡,給大眾車用戶添加oil屬性送加油卡。然后執(zhí)行這幾個(gè)函數(shù),修改相對應(yīng)的this指向即可。這樣的話就實(shí)現(xiàn)了我們想要的功能。這就是裝飾者模式。
裝飾者模式總結(jié)裝飾者模式就是在不創(chuàng)建新對象的情況下,給對象添加新的特性。

橋接模式

橋梁的作用主要就是連接岸的兩邊。在開發(fā)中,橋接模式的作用也是用于連接,只不過它連接的是抽象部分和實(shí)現(xiàn)部分。這么說可能很抽象,我們用具體的例子來展示。橋接模式在javascript中應(yīng)用最廣泛的就是事件監(jiān)聽。

 
box1
var oBox1 = document.getElementById("box1"); bindEvent(oBox1,"click",getBeerById) function getBeerById(){ var id = this.id; asyncRequest("GET","beer.uri?id="+id,function(resp) { console.log(resp.responseText); }) }

如上面代碼所示,我們定義了一個(gè)div,給id為box1的div綁定了點(diǎn)擊事件,事件函數(shù)為getBeerById。其中bindEvend點(diǎn)擊事件為抽象類,getBeerById為具體實(shí)現(xiàn)類。我們可以發(fā)現(xiàn)這個(gè)就實(shí)現(xiàn)類,也就是getBeerById函數(shù),只能作為事件觸發(fā)函數(shù),因?yàn)樗锩娴膖his.id依賴于點(diǎn)擊事件即抽象類。我們沒辦法對getBeerById進(jìn)行單元測試。現(xiàn)在假設(shè)我們又新增了一個(gè)div,它根據(jù)類名傳遞參數(shù),代碼如下所示:

box1
var oBox2 = document.getElementsByClassName("box2")[0]; bindEvent(oBox2,"click",getBeerByClassName) function getBeerByClassName(){ var className = this.className; asyncRequest("GET","beer.uri?id="+className,function(resp) { console.log(resp.responseText); }) }

上面這個(gè)事件處理函數(shù)getBeerByClassName,不再是根據(jù)id請求數(shù)據(jù)了,而是根據(jù)className請求數(shù)據(jù)。他們之間僅僅是傳遞參數(shù)的區(qū)別,根據(jù)代碼復(fù)用和抽象的原則,我們可能會將代碼公告部分抽離出來:

   function getBeerId(id){
     asyncRequest("GET","beer.uri?id="+id,function(resp) {
        console.log(resp.responseText);
      })
   }

將代碼公共部分抽離出來后,雖然提高了代碼的服用。但是帶來了新的問題,由于之前的具體實(shí)現(xiàn)是作為事件處理函數(shù),它依賴于抽象類即點(diǎn)擊事件。抽象后的代碼沒辦法作為事件處理函數(shù)了(因?yàn)橹巴ㄟ^this獲取id和className,現(xiàn)在是將其作為參數(shù)進(jìn)行封裝了),因此為了保證原來的功能,我們需要對代碼及性能修改,使用新的事件處理函數(shù)。

    //抽象類
    bindEvent(oBox1,"click",getBeerByIdBridge)

    //橋接函數(shù)
    function getBeerByIdBridge(e){
      getBeerById(this.id)
    }

    
    //具體類
    function getBeerById(id){
      asyncRequest("GET","beer.uri?id="+id,function(resp) {
        console.log(resp.responseText)
      })
    }

通過上面的代碼,我們可以知道,定義了一個(gè)函數(shù)getBeerByIdBridge來作為事件處理函數(shù)。但是這個(gè)函數(shù)并沒有實(shí)現(xiàn)具體的功能。具體功能的實(shí)現(xiàn)在getBeerById中,也就是說這個(gè)函數(shù)其實(shí)只是點(diǎn)擊事件和具體功能之間連接的橋梁。這就是橋接模式,這個(gè)函數(shù)就是橋接函數(shù)。通過上面的代碼,我們可以知道橋接模式就是抽象類和具體類之間抽離開來,使得他們能夠各自獨(dú)自變化,而不是互相依賴。
橋接模式的另一個(gè)應(yīng)用:用于連接多個(gè)類。
橋接模式不僅能夠用來連接抽象和具體實(shí)現(xiàn),而且還能夠用于連接多個(gè)類,這些多各類實(shí)現(xiàn)各部分功能,通過橋接模式實(shí)現(xiàn)完整的功能。看具體的代碼如下:

//A類
 class A {
    constructor(name,age){
      this.name = name;
      this.age = age;
    }
    showName(){
      console.log(this.name)
    }
  }
  //B類
  class B {
    constructor(job,sex){
      this.job = job;
      this.sex = sex;
    }
    showJob(){
      console.log(this.job)
    }
  }


  //橋接類
  class Bridge{
    constructor(){
      this.w = new A("劉亦菲",30);
      this.h = new B("actor","女")
    }
  }

  let bridge = new Bridge();
  console.log(bridge)
  bridge.w.showName()

如上面代碼所示,通過橋接類將類A和類B連接起來了,A類用于記錄姓名和年齡,B類用于記錄職業(yè)和性別,橋接類用于這些功能的所有的實(shí)現(xiàn),相當(dāng)于記錄一個(gè)人的完整信息。這樣的話我們進(jìn)行開發(fā)時(shí),可以分別對A類和B類進(jìn)行多帶帶開發(fā),各部分實(shí)現(xiàn)各自的功能,最后再通過橋接類實(shí)現(xiàn)完整功能。

橋接模式的總結(jié):橋接模式用于將抽象與其是實(shí)現(xiàn)隔離開來,以便二者獨(dú)立變化。這種模式對于事件驅(qū)動(dòng)的編程非常方便。另外橋接模式還可以用于將多個(gè)類連接起來,用于實(shí)現(xiàn)一個(gè)完整功能。

組合模式

組合:是指把一些零散的東西匯聚成一個(gè)整體,或者說把部分匯聚成整體。在開發(fā)中,組合模式同樣如此。
組合模式的定義:組合模式又稱部分-整體模式,將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),組合模式使得用戶對單個(gè)對象和組合對象的使用具有一致性。從組合模式的定義我們可以知道,組合模式有兩個(gè)特點(diǎn):
1.組合模式是部分與整體的層次關(guān)系,形成樹形結(jié)構(gòu)
組合模式的層次關(guān)系如下如圖所示:

從圖中我們可以看到組合模式的整個(gè)結(jié)構(gòu)是:一些葉子對象(也就是部分)組合成一級組合對象,這些組合對象又組合成一個(gè)組合對象,最終形成這種樹形結(jié)構(gòu)。我們以一個(gè)生活中實(shí)際的例子來舉例:
圖片描述

比如我們點(diǎn)餐,首先是整個(gè)菜單,然后菜單分為三類:主菜,飲料和甜品。每一類下面又進(jìn)行劃分,比如主菜包括土豆絲,西紅柿炒雞蛋,紅燒牛肉等。這樣形成了一個(gè)屬性菜單。
另外,提到樹形結(jié)構(gòu),我們學(xué)習(xí)的DOM樹就是最常見的屬性結(jié)構(gòu)。
2.組合模式使得用戶對單個(gè)對象和組合對象具有一致性。這句話怎么理解了,其實(shí)就是組合獨(dú)享和單個(gè)對象都具有一些相同的API(可以這么粗暴的理解),比如都定義成同名函數(shù)。
比如,我們以jQuery操作DOM為例。

  

如上面代碼所示:我們知道DOM結(jié)構(gòu)是樹形結(jié)構(gòu),同時(shí)使用jQuery時(shí),我們既可以對div使用css方法,又可以對div的子元素使用css方法,也就是說樹型結(jié)構(gòu)的組合和整體對象都能夠使用相同的css方法。同樣我們再以剛才的訂餐舉例:

從上面的圖中我們可以看出,所有的對象無論是葉子對象還是組合對象都具有相同的add方法,也就是說這個(gè)結(jié)構(gòu)的組合對象的API使用具有一致性。

組合模式總結(jié):組合模式牢記兩個(gè)特點(diǎn):

組合對象之間能夠形成樹形結(jié)構(gòu)

組合對象之間的API使用具有一致性。所謂一致性就是類似于同名函數(shù)。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100932.html

相關(guān)文章

  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實(shí)現(xiàn)文件分片斷點(diǎn)續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡單的方式。插....

    izhuhaodev 評論0 收藏0
  • 前端框架模式的變遷

    摘要:現(xiàn)在在前端的框架都是的模式,還有像和之類的變種獨(dú)特的單向數(shù)據(jù)流框架。只要將數(shù)據(jù)流進(jìn)行規(guī)范,那么原來的模式還是大有可為的。我們可以來看一下,框架的圖示從圖中,我們可以看到形成了一條到,再到,之后是的,一條單向數(shù)據(jù)流。 前言 前端框架的變遷,體系架構(gòu)的完善,使得我們只知道框架,卻不明白它背后的道理。我們應(yīng)該抱著一顆好奇心,在探索框架模式的變遷過程中,體會前人的一些理解和思考 本篇將講述的是...

    ssshooter 評論0 收藏0
  • 前端開發(fā)者手冊2019

    摘要:年,和前端開發(fā)者與應(yīng)用程序前端開發(fā)者之間產(chǎn)生了巨大的分歧。開發(fā)最常見的解決方案有手機(jī)和平板的原生應(yīng)用程序桌面應(yīng)用程序桌面應(yīng)用程序原生技術(shù)最后,前端開發(fā)者可以從瀏覽器開發(fā)中學(xué)習(xí)到,編寫代碼不需要考慮瀏覽器引擎的限制。 前端開發(fā)者手冊2019 Cody Lindley 編著 原文地址 本手冊由Frontend Masters贊助,通過深入現(xiàn)代化的前端工程課程來提高你的技能。 下載:PDF ...

    church 評論0 收藏0
  • 前端開發(fā)者手冊2019

    摘要:年,和前端開發(fā)者與應(yīng)用程序前端開發(fā)者之間產(chǎn)生了巨大的分歧。開發(fā)最常見的解決方案有手機(jī)和平板的原生應(yīng)用程序桌面應(yīng)用程序桌面應(yīng)用程序原生技術(shù)最后,前端開發(fā)者可以從瀏覽器開發(fā)中學(xué)習(xí)到,編寫代碼不需要考慮瀏覽器引擎的限制。 前端開發(fā)者手冊2019 Cody Lindley 編著 原文地址 本手冊由Frontend Masters贊助,通過深入現(xiàn)代化的前端工程課程來提高你的技能。 下載:PDF ...

    xiao7cn 評論0 收藏0
  • 前端開發(fā)者手冊2019

    摘要:年,和前端開發(fā)者與應(yīng)用程序前端開發(fā)者之間產(chǎn)生了巨大的分歧。開發(fā)最常見的解決方案有手機(jī)和平板的原生應(yīng)用程序桌面應(yīng)用程序桌面應(yīng)用程序原生技術(shù)最后,前端開發(fā)者可以從瀏覽器開發(fā)中學(xué)習(xí)到,編寫代碼不需要考慮瀏覽器引擎的限制。 前端開發(fā)者手冊2019 Cody Lindley 編著 原文地址 本手冊由Frontend Masters贊助,通過深入現(xiàn)代化的前端工程課程來提高你的技能。 下載:PDF ...

    鄒立鵬 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<