中介者模式的定義:通過⼀個中介者對象,其他所有的相關對象都通過該中介者對象來通信,⽽不是互相引⽤,當其中的⼀個對象發⽣改變時,隻需要通知中介者對象即可。通過中介者模式可以解除對象與對象之間的緊耦合關系。
例如:現實⽣活中,航線上的⻜機隻需要和機場的塔台通信就能确定航線和⻜⾏狀态,⽽不需要和所有⻜機通信。同時塔台作為中介者,知道每架⻜機的⻜⾏狀态,是以可以安排所有⻜機的起降和航線安排。
中介者模式适⽤的場景:例如購物⻋需求,存在商品選擇表單、顔⾊選擇表單、購買數量表單等等,都會觸發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;
裝飾者模式和代理模式的結構看起來⾮常相像,這兩種模式都描述了怎樣為對象提供 ⼀定程度上的間接
引⽤,它們的實作部分都保留了對另外⼀個對象的引⽤,并且向那個對象發送 請求。 代理模式和裝飾
者模式最重要的差別在于它們的意圖和設計⽬的。代理模式的⽬的是,當直接通路本體不⽅便或者不符
合需要時,為這個本體提供⼀個替代者。本體定義了關鍵功能,⽽代理提供或拒絕對它的通路,或者在