github所有關(guān)于設(shè)計模式的代碼:js學(xué)習(xí)設(shè)計模式記錄
1.適配器模式
使用場景:
舊接口與使用者不兼容,中間添加一個轉(zhuǎn)換接口轧苫。
當(dāng)他人已完成的代碼在格式上不滿足新需求時,用適配器模式改變疫蔓。
例子: 德國插座轉(zhuǎn)換為中國插座
class Adoptee{
specificRequest(){
return "德國插座"
}
}
class Adapter {
constructor(){
this.adoptee=new Adoptee()
}
request(){
let info=this.adoptee.specificRequest()
return `${info}-轉(zhuǎn)換-中國插座`
}
}
console.log(new Adapter().request())
2.裝飾器模式
使用場景: 舊的功能繼續(xù)沿用含懊,但是要在舊的功能上添加身冬、修飾一些部分
例子: 原Circle類可以畫一個圓,現(xiàn)要畫圓岔乔,并且給這個圓添加邊框
class Circle{
draw(){
console.log("畫一個圓")
}
}
class Decorator{
constructor(){
this.circle=new Circle()
}
draw(){
this.circle.draw()
this.fillBorder()
}
fillBorder(){
console.log("添加邊框")
}
}
new Decorator().draw()//畫一個圓 添加邊框
3.es7裝飾器介紹
類裝飾器
定義一個Demon的類酥筝,定義裝飾器decorator1,@decorator1
寫在calss Demon1
的前面
decorator1會獲取到參數(shù)target,也就是當(dāng)前的Demon1類重罪∮:撸可以在decorator1這個函數(shù)中對Demon1的屬性進行處理,如下在Demon1中添加一個靜態(tài)屬性decorator="i am decorator"
@decorator1
class Demon1{
}
function decorator1(target) {
target.decorator="i am decorator"
}
console.log(Demon1.decorator)//i am decorator
裝飾器對類的行為的改變剿配,是代碼編譯時發(fā)生的搅幅,而不是在運行時。裝飾器的原理如下
@decorator
class A{}
decorator(target){}
//相當(dāng)于↓↓
class A{}
A=decorator(A)||A
帶參數(shù)的裝飾器
@decorator2("new decorator")
class Demon2{
}
function decorator2(newValue){
return function (target) {
target.decorator=newValue
}
}
console.log(Demon2.decorator)//new decorator
@decorator2("new decorator")
執(zhí)行decorator2傳參“new decorator”呼胚,并且在decorator2的內(nèi)部返回不進行傳參時定義的裝飾器函數(shù)茄唐。
decorator2嵌套兩層function,第一層用來傳參蝇更,第二層是普通的裝飾器函數(shù)
@decorator2("new decorator")
class Demon2{
}
function decorator2(newValue){
return function (target) {
target.decorator=newValue
}
}
console.log(Demon2.decorator)//new decorator
常用裝飾器 :Mixin示例
Mixin相關(guān)知識點參考:Mixin
Mixin是JavaScript中用的最普遍的模式沪编,幾乎所有流行類庫都會有Mixin的實現(xiàn)。
Mixin是摻合年扩,混合蚁廓,糅合的意思,即可以就任意一個對象的全部或部分屬性拷貝到另一個對象上厨幻。
下面的例子中通過裝飾器mixin將別的對象的屬性相嵌、方法添加到Demon3中
assign知識點:ES6之Object.assign()詳解
function mixin(list){
return function (target) {
Object.assign(target.prototype,...list)
}
}
const append1={
getAppend1Name(){
console.log("append1")
}
}
const append2={
getAppend2Name(){
console.log("append2")
}
}
@mixin([ append1, append2])
class Demon3{
}
let demon3=new Demon3()
demon3.getAppend1Name()//append1
demon3.getAppend2Name()//append2
裝飾方法
readOnly 裝飾器
裝飾器總共接收三個參數(shù)target,value,description
在下面例子中target是Demon4,value是getName况脆,description是getName的屬性描述符
設(shè)置屬性描述符的writable為false饭宾,將getName屬性設(shè)置為只讀
function readOnly(target,value,description) {
description.writable=false
}
class Demon4 {
constructor(){
this.name="demon4"
}
@readOnly
getName(){
return this.name;
}
}
const demon4=new Demon4()
demon4.getName=function () {//報錯:Uncaught TypeError: Cannot assign to read only property 'getName' of object '#<Demon4>'
console.log("change")
}
修改getName時會報錯
log日志打印裝飾器
以下日志打印裝飾器在執(zhí)行setName時打印出舊的name值與新的name值
通過description.value重寫setName方法,使在調(diào)用原來的getName之前先console.log
function log(target,value,description) {
const oldValue=description.value
description.value=function (name) {
console.log(`previous name:${this.name} new name is:${name}`)
oldValue.call(this,arguments)
}
}
class Demon5{
constructor(){
this.name="demon5"
}
@log
setName(name){
this.name=name
}
}
const demon5=new Demon5()
demon5.setName("DEMON5")//previous name:demon5 new name is:DEMON5
建議不要手寫裝飾器格了,使用現(xiàn)成的裝飾器庫core-decorators.js