行為模式-中介者模式(The Mediator Pattern)

本文大部分內(nèi)容翻譯至《Pro Design Pattern In Swift》By Adam Freeman狱杰,一些地方做了些許修改,并將代碼升級(jí)到了Swift2.0,翻譯不當(dāng)之處望多包涵。

中介者模式(The Mediator Pattern)

用一個(gè)中介者對(duì)象來封裝一系列的對(duì)象交互。中介者使得各對(duì)象不需要顯式地相互引用弹砚,從而使其松散耦合,而且可以獨(dú)立地改變它們之間的交互枢希。


示例工程

Xcode Command Line Tool 工程:

Airplane.swift

struct Position {
    var distanceFromRunway:Int
    var height:Int
}

func == (lhs:Airplane, rhs:Airplane) -> Bool {
    return lhs.name == rhs.name
}

class Airplane : Equatable {
    var name:String
    var currentPosition:Position
    private var otherPlanes:[Airplane]
        
    init(name:String, initialPos:Position) {
        self.name = name
        self.currentPosition = initialPos
        self.otherPlanes = [Airplane]()
    }
        
    func addPlanesInArea(planes:Airplane...) {
        for plane in planes {
            otherPlanes.append(plane)
        }
    }
        
    func otherPlaneDidLand(plane:Airplane) {
        if let index = otherPlanes.indexOf(plane) {
           otherPlanes.removeAtIndex(index)
        }
    }
        
    func otherPlaneDidChangePosition(plane:Airplane) -> Bool {
        return plane.currentPosition.distanceFromRunway == self.currentPosition.distanceFromRunway && abs(plane.currentPosition.height - self.currentPosition.height) < 1000
    }
        
    func changePosition(newPosition:Position) {
        self.currentPosition = newPosition
        for plane in otherPlanes {
            if (plane.otherPlaneDidChangePosition(self)) {
                print("\(name): Too close! Abort!")
                return
            }
        }
        print("\(name): Position changed")
    }
        
    func land() {
        self.currentPosition = Position(distanceFromRunway: 0, height: 0)
        for plane in otherPlanes {
            plane.otherPlaneDidLand(self)
        }
        print("\(name): Landed")
    }
}

Airplane類用來代表接近機(jī)場(chǎng)的一架飛機(jī)并且用Position結(jié)構(gòu)體來追蹤它的位置桌吃。當(dāng)然機(jī)場(chǎng)也可能有其它的飛機(jī)在接近,所以每一個(gè)Airplane對(duì)象都會(huì)追蹤其它接近的飛機(jī)苞轿,以免距離太近茅诱。然后我們看看main.swift中的應(yīng)用:

// initial setup
let british = Airplane(name: "BA706", initialPos: Position(distanceFromRunway: 11, height: 21000))

// plane approaches airport
british.changePosition(Position(distanceFromRunway: 8, height: 10000))
british.changePosition(Position(distanceFromRunway: 2, height: 5000))
british.changePosition(Position(distanceFromRunway: 1, height: 1000))

// plane lands
british.land()

運(yùn)行程序:

BA706: Position changed
BA706: Position changed
BA706: Position changed
BA706: Landed

理解中介者模式解決的問題

當(dāng)有幾架飛機(jī)同時(shí)接近機(jī)場(chǎng)時(shí),問題出現(xiàn)了搬卒。

main.swift

// initial setup
let british = Airplane(name: "BA706", initialPos:
    Position(distanceFromRunway: 11, height: 21000))

// new plane arrives
let american = Airplane(name: "AA101", initialPos: Position(distanceFromRunway: 12, height: 22000))
british.addPlanesInArea(american)
american.addPlanesInArea(british)
// plane approaches airport
british.changePosition(Position(distanceFromRunway: 8, height: 10000))
british.changePosition(Position(distanceFromRunway: 2, height: 5000))
british.changePosition(Position(distanceFromRunway: 1, height: 1000))

// new plane arrives
let cathay = Airplane(name: "CX200", initialPos: Position(distanceFromRunway: 13, height: 22000))
british.addPlanesInArea(cathay)
american.addPlanesInArea(cathay)
cathay.addPlanesInArea(british, american)
// plane lands
british.land()
// plane moves too close
cathay.changePosition(Position(distanceFromRunway: 12, height: 22000))

運(yùn)行程序:

BA706: Position changed
BA706: Position changed
BA706: Position changed
BA706: Landed
CX200: Too close! Abort!

這里只有三架飛機(jī)而已瑟俭,但是main.swift中的代碼已經(jīng)變得十分復(fù)雜臃腫了。



當(dāng)我們?cè)僭黾右患茱w機(jī)的時(shí)候秀睛,就更難受了尔当。



理解中介者模式

中介者模式通過引入一個(gè)中介者對(duì)象來簡化兩個(gè)對(duì)象或者更多對(duì)象之間的通信莲祸。為了使得對(duì)象間低耦合蹂安,中介者保持追蹤所有對(duì)象的狀態(tài)并且傳輸它們之間的通信椭迎。



實(shí)現(xiàn)中介者模式

中介者模式的核心是有一對(duì)協(xié)議:一個(gè)是定義同事對(duì)象的協(xié)議,另一個(gè)是中介者的協(xié)議田盈。

Mediator.swift

protocol Peer {
    var name:String {get}
    func otherPlaneDidChangePosition(position:Position) -> Bool
}

protocol Mediator {
    func registerPeer(peer:Peer)
    func unregisterPeer(peer:Peer)
    func changePosition(peer:Peer, pos:Position) -> Bool
}

定義中介者類

下面我們定義中介者類:

Mediator.swift

......

class AirplaneMediator : Mediator {
    private var peers:[String:Peer]
    
    init() {
        peers = [String:Peer]()
    }

    func registerPeer(peer: Peer) {
        self.peers[peer.name] = peer
    }
    
    func unregisterPeer(peer: Peer) {
        self.peers.removeValueForKey(peer.name)
    }
    
    func changePosition(peer:Peer, pos:Position) -> Bool {
        for storedPeer in peers.values {
            if (peer.name != storedPeer.name
                && storedPeer.otherPlaneDidChangePosition(pos)) {
                return true
            }
        }
        return false
    }
}
.....

定義同事類

Airplane.swift

struct Position {
    var distanceFromRunway:Int
    var height:Int
}

class Airplane : Peer {
    var name:String
    var currentPosition:Position
    var mediator:Mediator
        
    init(name:String, initialPos:Position, mediator: Mediator) {
        self.name = name
        self.currentPosition = initialPos
        self.mediator = mediator
        mediator.registerPeer(self)
    }
        
    func otherPlaneDidChangePosition(position:Position) -> Bool {
        return position.distanceFromRunway == self.currentPosition.distanceFromRunway && abs(position.height - self.currentPosition.height) < 1000
    }

    func changePosition(newPosition:Position) {
        self.currentPosition = newPosition
        if (mediator.changePosition(self, pos: self.currentPosition) == true) {
            print("\(name): Too close! Abort!")
            return
        }
        print("\(name): Position changed")
    }
        
    func land() {
        self.currentPosition = Position(distanceFromRunway: 0, height: 0)
        mediator.unregisterPeer(self)
        print("\(name): Landed")
    }
}

最后我們看main.swift中的應(yīng)用:

let mediator:Mediator = AirplaneMediator()
// initial setup
let british = Airplane(name: "BA706", initialPos:
    Position(distanceFromRunway: 11, height: 21000), mediator:mediator)
// new plane arrives
let american = Airplane(name: "AA101", initialPos: Position(distanceFromRunway: 12, height: 22000),
    mediator:mediator)
// plane approaches airport
british.changePosition(Position(distanceFromRunway: 8, height: 10000))
british.changePosition(Position(distanceFromRunway: 2, height: 5000))
british.changePosition(Position(distanceFromRunway: 1, height: 1000))
// new plane arrives
let cathay = Airplane(name: "CX200", initialPos: Position(distanceFromRunway: 13, height: 22000),
    mediator:mediator)
// plane lands
british.land()
// plane moves too close
cathay.changePosition(Position(distanceFromRunway: 12, height: 22000))

運(yùn)行程序:

BA706: Position changed
BA706: Position changed
BA706: Position changed
BA706: Landed
CX200: Too close! Abort!

中介者并發(fā)保護(hù)

對(duì)中介者進(jìn)行并發(fā)保護(hù)保證了同事類集合不會(huì)損壞畜号。

Mediator.swift

import Foundation
protocol Peer {
    var name:String {get}
    func otherPlaneDidChangePosition(position:Position) -> Bool
}

protocol Mediator {
    func registerPeer(peer:Peer)
    func unregisterPeer(peer:Peer)
    func changePosition(peer:Peer, pos:Position) -> Bool
}

class AirplaneMediator : Mediator {
    private var peers:[String:Peer]
    private let queue = dispatch_queue_create("dictQ", DISPATCH_QUEUE_CONCURRENT)
    
    init() {
        peers = [String:Peer]()
    }

    func registerPeer(peer: Peer) {
        dispatch_barrier_sync(queue){[weak self] in
            self!.peers[peer.name] = peer
        }
    }
    
    func unregisterPeer(peer: Peer) {
        dispatch_barrier_sync(queue){[weak self] in
             self!.peers.removeValueForKey(peer.name)
        }
    }
    
    func changePosition(peer:Peer, pos:Position) -> Bool {
        var result = false
        dispatch_sync(self.queue){[weak self] in
            for storedPeer in self!.peers.values {
                if (peer.name != storedPeer.name && storedPeer.otherPlaneDidChangePosition(pos)) {
                    result = true
                }
            }
        }
        return result
    }
}

我們想要能并發(fā)的去讀取同事類集合的數(shù)據(jù)直到要修改它,因此用了一個(gè)并行隊(duì)列并用同步的方式提交讀操作允瞧。用dispatch_barrier_sync方法去獲得唯一的訪問來修改简软。


并發(fā)保護(hù)同事類

Airplane.swift

import Foundation
struct Position {
    var distanceFromRunway:Int
    var height:Int
}

class Airplane : Peer {
    var name:String
    var currentPosition:Position
    var mediator:Mediator
    let queue = dispatch_queue_create("posQ", DISPATCH_QUEUE_CONCURRENT)
        
    init(name:String, initialPos:Position, mediator: Mediator) {
        self.name = name
        self.currentPosition = initialPos
        self.mediator = mediator
        mediator.registerPeer(self)
    }
        
    func otherPlaneDidChangePosition(position:Position) -> Bool {
        var result = false
        dispatch_sync(queue){[weak self] in
            result = position.distanceFromRunway == self!.currentPosition.distanceFromRunway && abs(position.height - self!.currentPosition.height) < 1000
        }
        return result
    }

    func changePosition(newPosition:Position) {
        dispatch_barrier_sync(queue){[weak self] in
            self!.currentPosition = newPosition
            if (self!.mediator.changePosition(self!, pos: self!.currentPosition) == true) {
                print("\(self!.name): Too close! Abort!")
                return
            }
            print("\(self!.name): Position changed")
        }
    }
        
    func land() {
        dispatch_barrier_sync(queue){[weak self] in
            self!.currentPosition = Position(distanceFromRunway: 0, height: 0)
            self!.mediator.unregisterPeer(self!)
            print("\(self!.name): Landed")
        }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市述暂,隨后出現(xiàn)的幾起案子痹升,更是在濱河造成了極大的恐慌,老刑警劉巖畦韭,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疼蛾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡艺配,警方通過查閱死者的電腦和手機(jī)察郁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來转唉,“玉大人皮钠,你說我怎么就攤上這事≡ǎ” “怎么了麦轰?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砖织。 經(jīng)常有香客問我原朝,道長,這世上最難降的妖魔是什么镶苞? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任喳坠,我火速辦了婚禮,結(jié)果婚禮上茂蚓,老公的妹妹穿的比我還像新娘壕鹉。我一直安慰自己,他們只是感情好聋涨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布晾浴。 她就那樣靜靜地躺著,像睡著了一般牍白。 火紅的嫁衣襯著肌膚如雪脊凰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音狸涌,去河邊找鬼切省。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帕胆,可吹牛的內(nèi)容都是我干的朝捆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼懒豹,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼芙盘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起脸秽,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤儒老,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后记餐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贷盲,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年剥扣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了巩剖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钠怯,死狀恐怖佳魔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晦炊,我是刑警寧澤鞠鲜,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站断国,受9級(jí)特大地震影響贤姆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稳衬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一霞捡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧薄疚,春花似錦碧信、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至板丽,卻和暖如春呈枉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國打工猖辫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酥泞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓住册,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瓮具。 傳聞我的和親對(duì)象是個(gè)殘疾皇子荧飞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容