JavaScript 設(shè)計(jì)模式 – 通過示例進(jìn)行解釋_第1頁
JavaScript 設(shè)計(jì)模式 – 通過示例進(jìn)行解釋_第2頁
JavaScript 設(shè)計(jì)模式 – 通過示例進(jìn)行解釋_第3頁
JavaScript 設(shè)計(jì)模式 – 通過示例進(jìn)行解釋_第4頁
JavaScript 設(shè)計(jì)模式 – 通過示例進(jìn)行解釋_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

?大家好!在本文中,我將解釋什么是設(shè)計(jì)模式以及它們?yōu)楹斡杏?。目錄什么是設(shè)計(jì)模式?創(chuàng)意設(shè)計(jì)模式單例模式工廠方法模式抽象工廠模式建造者模式原型模式結(jié)構(gòu)設(shè)計(jì)模式適配器模式裝飾模式立面圖案代理模式行為設(shè)計(jì)模式責(zé)任鏈模式迭代器模式觀察者模式什么是設(shè)計(jì)模式?設(shè)計(jì)模式因《設(shè)計(jì)模式:可重用面向?qū)ο筌浖脑亍芬粫餍衅饋?,該書由四位C++工程師于1994年出版。本書探討了面向?qū)ο缶幊痰墓δ芎拖葳?,并描述?3種有用的模式,您可以實(shí)現(xiàn)這些模式來解決常見的編程問題。這些模式不是算法或特定的實(shí)現(xiàn)。它們更像是想法、觀點(diǎn)和抽象概念,在某些情況下可用于解決特定類型的問題。模式的具體實(shí)現(xiàn)可能會根據(jù)許多不同的因素而有所不同。但重要的是它們背后的概念,以及它們?nèi)绾螏椭覀優(yōu)槲覀兊膯栴}找到更好的解決方案。話雖這么說,請記住這些模式是在考慮OOPC++編程的情況下想到的。當(dāng)涉及更現(xiàn)代的語言(如JavaScript或其他編程范例)時,這些模式可能不會同樣有用,甚至可能會向我們的代碼添加不必要的樣板文件。盡管如此,我認(rèn)為了解它們作為一般編程知識還是有好處的。旁注:如果您不熟悉編程范例或OOP,我最近寫了兩篇關(guān)于這些主題的文章。無論如何...現(xiàn)在我們已經(jīng)完成了介紹,設(shè)計(jì)模式分為三個主要類別:創(chuàng)建模式、結(jié)構(gòu)模式和行為模式。讓我們簡要探討一下它們。創(chuàng)意設(shè)計(jì)模式創(chuàng)建模式由用于創(chuàng)建對象的不同機(jī)制組成。單例模式Singleton是一種設(shè)計(jì)模式,可確保一個類只有一個不可變的實(shí)例。簡單地說,單例模式由一個無法復(fù)制或修改的對象組成。當(dāng)我們想要為我們的應(yīng)用程序提供一些不可變的單點(diǎn)事實(shí)時,它通常很有用。舉例來說,我們希望將應(yīng)用程序的所有配置都放在一個對象中。我們希望禁止對該對象進(jìn)行任何復(fù)制或修改。實(shí)現(xiàn)此模式的兩種方法是使用對象文字和類:constConfig={

start:()=>console.log('Apphasstarted'),

update:()=>console.log('Apphasupdated'),}//WefreezetheobjecttopreventnewpropertiesbeingaddedandexistingpropertiesbeingmodifiedorremovedObject.freeze(Config)Config.start()//"Apphasstarted"Config.update()//"Apphasupdated"C="Robert"http://Wetrytoaddanewkeyconsole.log(Config)//Andverifyitdoesn'twork:{start:[Function:start],update:[Function:update]}使用對象字面量classConfig{

constructor(){}

start(){console.log('Apphasstarted')}

update(){console.log('Apphasupdated')}}

constinstance=newConfig()Object.freeze(instance)使用類工廠方法模式工廠方法模式提供了一個用于創(chuàng)建對象的接口,這些對象在創(chuàng)建后可以進(jìn)行修改。最酷的一點(diǎn)是,創(chuàng)建對象的邏輯集中在一個地方,從而簡化并更好地組織我們的代碼。這種模式被大量使用,也可以通過兩種不同的方式實(shí)現(xiàn),通過類或工廠函數(shù)(返回對象的函數(shù))。classAlien{

constructor(name,phrase){

=name

this.phrase=phrase

this.species="alien"

}

fly=()=>console.log("Zzzzzziiiiiinnnnnggggg!!")

sayPhrase=()=>console.log(this.phrase)}constalien1=newAlien("Ali","I'mAlithealien!")console.log()//output:"Ali"使用類functionAlien(name,phrase){

=name

this.phrase=phrase

this.species="alien"}Atotype.fly=()=>console.log("Zzzzzziiiiiinnnnnggggg!!")Atotype.sayPhrase=()=>console.log(this.phrase)constalien1=newAlien("Ali","I'mAlithealien!")console.log()//output"Ali"console.log(alien1.phrase)//output"I'mAlithealien!"alien1.fly()//output"Zzzzzziiiiiinnnnnggggg"使用工廠函數(shù)抽象工廠模式抽象工廠模式允許我們在不指定具體類的情況下生成相關(guān)對象系列。當(dāng)我們需要創(chuàng)建僅共享某些屬性和方法的對象時,它非常有用。它的工作方式是通過呈現(xiàn)一個與客戶端交互的抽象工廠。該抽象工廠根據(jù)相應(yīng)的邏輯調(diào)用相應(yīng)的具體工廠。該具體工廠就是返回最終對象的工廠。基本上,它只是在工廠方法模式上添加了一個抽象層,以便我們可以創(chuàng)建許多不同類型的對象,但仍然與單個工廠函數(shù)或類交互。讓我們通過一個例子來看看。假設(shè)我們正在為一家汽車公司建模一個系統(tǒng),該公司當(dāng)然生產(chǎn)汽車,但也生產(chǎn)摩托車和卡車。//Wehaveaclassor"concretefactory"foreachvehicletypeclassCar{

constructor(){

="Car"

this.wheels=4

}

turnOn=()=>console.log("Chacabúm!!")}classTruck{

constructor(){

="Truck"

this.wheels=8

}

turnOn=()=>console.log("RRRRRRRRUUUUUUUUUMMMMMMMMMM!!")}classMotorcycle{

constructor(){

="Motorcycle"

this.wheels=2

}

turnOn=()=>console.log("sssssssssssssssssssssssssssssshhhhhhhhhhham!!")}//Andandabstractfactorythatworksasasinglepointofinteractionforourclients//Giventhetypeparameteritreceives,itwillcallthecorrespondingconcretefactoryconstvehicleFactory={

createVehicle:function(type){

switch(type){

case"car":

returnnewCar()

case"truck":

returnnewTruck()

case"motorcycle":

returnnewMotorcycle()

default:

returnnull

}

}}constcar=vehicleFactory.createVehicle("car")//Car{turnOn:[Function:turnOn],name:'Car',wheels:4}consttruck=vehicleFactory.createVehicle("truck")//Truck{turnOn:[Function:turnOn],name:'Truck',wheels:8}constmotorcycle=vehicleFactory.createVehicle("motorcycle")//Motorcycle{turnOn:[Function:turnOn],name:'Motorcycle',wheels:2}建造者模式Builder模式用于按“步驟”創(chuàng)建對象。通常我們會有函數(shù)或方法向我們的對象添加某些屬性或方法。這種模式最酷的一點(diǎn)是我們將屬性和方法的創(chuàng)建分離到不同的實(shí)體中。如果我們有一個類或工廠函數(shù),我們實(shí)例化的對象將始終具有該類/工廠中聲明的所有屬性和方法。但是使用構(gòu)建器模式,我們可以創(chuàng)建一個對象并僅應(yīng)用我們需要的“步驟”,這是一種更靈活的方法。這與對象組合有關(guān),這是我在這里討論的主題。//Wedeclareourobjectsconstbug1={

name:"BuggyMcFly",

phrase:"Yourdebuggerdoesn'tworkwithme!"}constbug2={

name:"MartinianoBuggland",

phrase:"Can'ttouchthis!Nananana..."}//ThesefunctionstakeanobjectasparameterandaddamethodtothemconstaddFlyingAbility=obj=>{

obj.fly=()=>console.log(`Now${}canfly!`)}constaddSpeechAbility=obj=>{

obj.saySmthg=()=>console.log(`${}walksthewalkandtalksthetalk!`)}//FinallywecallthebuilderfunctionspassingtheobjectsasparametersaddFlyingAbility(bug1)bug1.fly()//output:"NowBuggyMcFlycanfly!"addSpeechAbility(bug2)bug2.saySmthg()//output:"MartinianoBugglandwalksthewalkandtalksthetalk!"原型模式原型模式允許您使用另一個對象作為藍(lán)圖來創(chuàng)建一個對象,并繼承其屬性和方法。如果您使用JavaScript一段時間,您可能熟悉原型繼承以及JavaScript的工作原理。最終結(jié)果與我們使用類獲得的結(jié)果非常相似,但具有更多的靈活性,因?yàn)閷傩院头椒梢栽趯ο笾g共享,而不依賴于同一個類。//Wedeclareourprototypeobjectwithtwomethodsconstenemy={

attack:()=>console.log("PimPamPum!"),

flyAway:()=>console.log("Flyyyylikeaneagle!")}//Wedeclareanotherobjectthatwillinheritfromourprototypeconstbug1={

name:"BuggyMcFly",

phrase:"Yourdebuggerdoesn'tworkwithme!"}//WithsetPrototypeOfwesettheprototypeofourobjectObject.setPrototypeOf(bug1,enemy)//WithgetPrototypeOfwereadtheprototypeandconfirmtheprevioushasworkedconsole.log(Object.getPrototypeOf(bug1))//{attack:[Function:attack],flyAway:[Function:flyAway]}console.log(bug1.phrase)//Yourdebuggerdoesn'tworkwithme!console.log(bug1.attack())//PimPamPum!console.log(bug1.flyAway())//Flyyyylikeaneagle!結(jié)構(gòu)設(shè)計(jì)模式結(jié)構(gòu)模式是指如何將對象和類組裝成更大的結(jié)構(gòu)。適配器模式適配器允許兩個具有不兼容

接口的對象相互交互。例如,假設(shè)您的應(yīng)用程序查詢一個返回XML的API,并將該信息發(fā)送到另一個API來處理該信息。但處理API需要JSON。由于兩個接口不兼容,因此您無法發(fā)送收到的信息。你需要先適應(yīng)它。我們可以用一個更簡單的例子來形象化相同的概念。假設(shè)我們有一系列城市和一個返回這些城市擁有的最大居民數(shù)量的函數(shù)。我們數(shù)組中的居民數(shù)量以百萬為單位,但我們要添加一個新城市,其居民沒有百萬轉(zhuǎn)換://OurarrayofcitiesconstcitiesHabitantsInMillions=[

{city:"London",habitants:8.9},

{city:"Rome",habitants:2.8},

{city:"Newyork",habitants:8.8},

{city:"Paris",habitants:2.1},]//ThenewcitywewanttoaddconstBuenosAires={

city:"BuenosAires",

habitants:3100000}//OuradapterfunctiontakesourcityandconvertsthehabitantspropertytothesameformatalltheothercitieshaveconsttoMillionsAdapter=city=>{city.habitants=parseFloat((city.habitants/1000000).toFixed(1))}toMillionsAdapter(BuenosAires)//WeaddthenewcitytothearraycitiesHabitantsInMillions.push(BuenosAires)//AndthisfunctionreturnsthelargesthabitantsnumberconstMostHabitantsInMillions=()=>{

returnMath.max(...citiesHabitantsInMillions.map(city=>city.habitants))}console.log(MostHabitantsInMillions())//8.9裝飾模式裝飾器模式允許您通過將新行為放置在包含行為的包裝對象內(nèi)來將新行為附加到對象上。如果您對React和高階組件(HOC)有一定的了解,這種方法可能會讓您感到熟悉。從技術(shù)上講,React中的組件是函數(shù),而不是對象。但是,如果我們考慮一下ReactContext或Memo的方式,我們可以看到我們將一個組件作為子組件傳遞給這個HOC,并且由于這個子組件能夠訪問某些功能。在此示例中,我們可以看到ContextProvider組件正在接收子項(xiàng)作為props:import{useState}from'react'importContextfrom'./Context'constContextProvider:React.FC=({children})=>{

const[darkModeOn,setDarkModeOn]=useState(true)

const[englishLanguage,setEnglishLanguage]=useState(true)

return(

<Context.Providervalue={{

darkModeOn,

setDarkModeOn,

englishLanguage,

setEnglishLanguage

}}>

{children}

</Context.Provider>

)}exportdefaultContextProvider然后我們將整個應(yīng)用程序圍繞它:exportdefaultfunctionApp(){

return(

<ContextProvider>

<Router>

<ErrorBoundary>

<Suspensefallback={<></>}>

<Header/>

</Suspense>

<Routes>

<Routepath='/'element={<Suspensefallback={<></>}><AboutPage/></Suspense>}/>

<Routepath='/projects'element={<Suspensefallback={<></>}><ProjectsPage/></Suspense>}/>

<Routepath='/projects/helpr'element={<Suspensefallback={<></>}><HelprProject/></Suspense>}/>

<Routepath='/projects/myWebsite'element={<Suspensefallback={<></>}><MyWebsiteProject/></Suspense>}/>

<Routepath='/projects/mixr'element={<Suspensefallback={<></>}><MixrProject/></Suspense>}/>

<Routepath='/projects/shortr'element={<Suspensefallback={<></>}><ShortrProject/></Suspense>}/>

<Routepath='/curriculum'element={<Suspensefallback={<></>}><CurriculumPage/></Suspense>}/>

<Routepath='/blog'element={<Suspensefallback={<></>}><BlogPage/></Suspense>}/>

<Routepath='/contact'element={<Suspensefallback={<></>}><ContactPage/></Suspense>}/>

</Routes>

</ErrorBoundary>

</Router>

</ContextProvider>

)}之后,使用該useContext鉤子,我可以從應(yīng)用程序中的任何組件訪問上下文中定義的狀態(tài)。constAboutPage:React.FC=()=>{

const{darkModeOn,englishLanguage}=useContext(Context)

return(...)}exportdefaultAboutPage同樣,這可能不是本書作者在撰寫此模式時所想到的確切實(shí)現(xiàn),但我相信想法是相同的。將一個對象放置在另一個對象中,以便它可以訪問某些功能。;)立面圖案外觀模式為庫、框架或任何其他復(fù)雜的類集提供了簡化的接口。嗯……我們可能可以為此舉出很多例子,對嗎?我的意思是,React本身或任何無數(shù)的庫幾乎用于與軟件開發(fā)相關(guān)的任何內(nèi)容。特別是當(dāng)我們考慮聲明式編程時,一切都是為了提供抽象,從而隱藏開發(fā)人員眼中的復(fù)雜性。一個簡單的例子就是JavaScript的map、sort、reduce和filter函數(shù),它們的工作原理就像for底層的良好循環(huán)一樣。另一個例子可以是當(dāng)今用于UI開發(fā)的任何庫,例如MUI。正如我們在下面的示例中看到的,這些庫為我們提供了帶有內(nèi)置特性和功能的組件,可以幫助我們更快、更輕松地構(gòu)建代碼。但所有這些在編譯后都會變成簡單的HTML元素,這是瀏覽器唯一能理解的東西。這些組件只是抽象概念,旨在讓我們的生活更輕松。import*asReactfrom'react';importTablefrom'@mui/material/Table';importTableBodyfrom'@mui/material/TableBody';importTableCellfrom'@mui/material/TableCell';importTableContainerfrom'@mui/material/TableContainer';importTableHeadfrom'@mui/material/TableHead';importTableRowfrom'@mui/material/TableRow';importPaperfrom'@mui/material/Paper';functioncreateData(

name:string,

calories:number,

fat:number,

carbs:number,

protein:number,){

return{name,calories,fat,carbs,protein};}constrows=[

createData('Frozenyoghurt',159,6.0,24,4.0),

createData('Icecreamsandwich',237,9.0,37,4.3),

createData('Eclair',262,16.0,24,6.0),

createData('Cupcake',305,3.7,67,4.3),

createData('Gingerbread',356,16.0,49,3.9),];exportdefaultfunctionBasicTable(){

return(

<TableContainercomponent={Paper}>

<Tablesx={{minWidth:650}}aria-label="simpletable">

<TableHead>

<TableRow>

<TableCell>Dessert(100gserving)</TableCell>

<TableCellalign="right">Calories</TableCell>

<TableCellalign="right">Fat (g)</TableCell>

<TableCellalign="right">Carbs (g)</TableCell>

<TableCellalign="right">Protein (g)</TableCell>

</TableRow>

</TableHead>

<TableBody>

{rows.map((row)=>(

<TableRow

key={}

sx={{'&:last-childtd,&:last-childth':{border:0}}}

>

<TableCellcomponent="th"scope="row">

{}

</TableCell>

<TableCellalign="right">{row.calories}</TableCell>

<TableCellalign="right">{row.fat}</TableCell>

<TableCellalign="right">{row.carbs}</TableCell>

<TableCellalign="right">{tein}</TableCell>

</TableRow>

))}

</TableBody>

</Table>

</TableContainer>

);}代理模式代理模式為另一個對象提供替代或占位符。這個想法是控制對原始對象的訪問,在請求到達(dá)實(shí)際原始對象之前或之后執(zhí)行某種操作。再說一遍,如果您熟悉ExpressJS,這可能會讓您感到熟悉。Express是一個用于開發(fā)NodeJSAPI的框架,它的特點(diǎn)之一就是使用中間件。中間件只不過是我們可以在任何請求到達(dá)端點(diǎn)之前、中間或之后執(zhí)行的代碼片段。讓我們看一個例子。這里我有一個驗(yàn)證身份驗(yàn)證令牌的函數(shù)。不要太關(guān)注它是如何做到這一點(diǎn)的。只需知道它接收令牌作為參數(shù),一旦完成,它就會調(diào)用該next()函數(shù)。constjwt=require('jsonwebtoken')module.exports=functionauthenticateToken(req,res,next){

constauthHeader=req.headers['authorization']

consttoken=authHeader&&authHeader.split('')[1]

if(token===null)returnres.status(401).send(JSON.stringify('Noaccesstokenprovided'))

jwt.verify(token,process.env.TOKEN_SECRET,(err,user)=>{

if(err)returnres.status(403).send(JSON.stringify('Wrongtokenprovided'))

req.user=user

next()

})}該函數(shù)是一個中間件,我們可以通過以下方式在API的任何端點(diǎn)中使用它。我們只需將中間件放置在端點(diǎn)地址之后和端點(diǎn)函數(shù)聲明之前:router.get('/:jobRecordId',authenticateToken,async(req,res)=>{

try{

constjob=awaitJobRecord.findOne({_id:req.params.jobRecordId})

res.status(200)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論