天天看點

中介者模式+裝飾器模式

      中介者模式的定義:通過⼀個中介者對象,其他所有的相關對象都通過該中介者對象來通信,⽽不是互相引⽤,當其中的⼀個對象發⽣改變時,隻需要通知中介者對象即可。通過中介者模式可以解除對象與對象之間的緊耦合關系。

例如:現實⽣活中,航線上的⻜機隻需要和機場的塔台通信就能确定航線和⻜⾏狀态,⽽不需要和所有⻜機通信。同時塔台作為中介者,知道每架⻜機的⻜⾏狀态,是以可以安排所有⻜機的起降和航線安排。

中介者模式适⽤的場景:例如購物⻋需求,存在商品選擇表單、顔⾊選擇表單、購買數量表單等等,都會觸發change事件,那麼可以通過中介者來轉發處理這些事件,實作各個事件間的解耦,僅僅維護中介者對象即可。redux,vuex 都屬于中介者模式的實際應⽤,我們把共享的資料,抽離成⼀個單獨的store, 每個都通過store這個中介來操作對象

⽬的就是減少耦合。

       裝飾者模式的定義:在不改變對象⾃身的基礎上,在程式運⾏期間給對象動态地添加⽅法。常⻅應⽤,react的⾼階元件, 或者react-redux中的@connect 或者⾃⼰定義⼀些⾼階元件

       import React from 'react'

       const withLog = Component=>{

      // 類元件

     class NewComponent extends React.Component{

     componentWillMount(){

     console.time(`CompoentRender`)

     console.log(`準備完畢了`)

     }

     render(){

     return <Component {...this.props}></Component>

     }

      componentDidMount(){

           console.timeEnd(`CompoentRender`)

           console.log(`渲染完畢了`)

     }

     }

     return NewComponent

      }

     export {withLog}

     @withLog

     class XX

export const connect = (mapStateToProps = state => state, mapDispatchToProps =

{}) => (WrapComponent) => {

return class ConnectComponent extends React.Component {

static contextTypes = {

store: PropTypes.object

}

constructor(props, context) {

super(props, context)

this.state = {

props: {}

}

}

componentDidMount() {

const { store } = this.context

// 目前狀态 update 後, 放⼊監聽器中, ⽤于下⼀次的更新(每次 dispatch 後會執⾏

subscribe 中的所有函數)

store.subscribe(() => this.update())

this.update()

}

update() {

const { store } = this.context

const stateProps = mapStateToProps(store.getState())

const dispatchProps = bindActionCreators(mapDispatchToProps,

store.dispatch)

this.setState({

props: {

...this.state.props,

...stateProps,

...dispatchProps

}

})

}

render() {

return <WrapComponent {...this.state.props}></WrapComponent>

}

}

}

假設我們在編寫⼀個⻜機⼤戰的遊戲,随着經驗值的增加,我們操作的⻜機對象可以更新成更厲害的⻜機,⼀開始這些⻜機隻能發射普通的⼦彈,升到第⼆級時可以發射飛彈,升到第三級時可以發射原⼦彈。

Function.prototype.before = function( beforefn ){

var __self = this; // 儲存原函數的引⽤

return function(){ // 傳回包含了原函數和新函數的"代理"函數

beforefn.apply( this, arguments ); // 執⾏新函數,且保證 this 不被劫持,新函

數接受的參數 // 也會被原封不動地傳⼊原函數,新函數在原函數之前執⾏

return __self.apply( this, arguments ); // 執⾏原函數并傳回原函數的執⾏結

果, // 并且保證 this 不被劫持

} }

Function.prototype.after = function( afterfn ){

var __self = this;

return function(){

var ret = __self.apply( this, arguments );

afterfn.apply( this, arguments );

return ret;

}

};

                ⽐如⻚⾯中有⼀個登入 button,點選這個 button 會彈出登入浮層,與此同時要進⾏資料上報, 來統計有多少⽤戶點選了這個登入 button

var showLogin = function(){

console.log( '打開登入浮層' );

log( this.getAttribute( 'tag' ) );

}

var log = function( tag ){

console.log( '上報标簽為: ' + tag );

(new Image).src = 'http:// xxx.com/report?tag=' + tag;

}

document.getElementById( 'button' ).onclick = showLogin;

使⽤裝飾器

var showLogin = function(){

console.log( '打開登入浮層' );

}

var log = function(){

console.log( '上報标簽為: ' + this.getAttribute( 'tag' ) );

}

showLogin = showLogin.after( log ); // 打開登入浮層之後上報資料

document.getElementById( 'button' ).onclick = showLogin;

裝飾者模式和代理模式的結構看起來⾮常相像,這兩種模式都描述了怎樣為對象提供 ⼀定程度上的間接

引⽤,它們的實作部分都保留了對另外⼀個對象的引⽤,并且向那個對象發送 請求。 代理模式和裝飾

者模式最重要的差別在于它們的意圖和設計⽬的。代理模式的⽬的是,當直接通路本體不⽅便或者不符

合需要時,為這個本體提供⼀個替代者。本體定義了關鍵功能,⽽代理提供或拒絕對它的通路,或者在

繼續閱讀