美文网首页
行为模式-中介者模式(The Mediator Pattern)

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

作者: ZhouMac | 来源:发表于2016-05-14 19:33 被阅读100次

    本文大部分内容翻译至《Pro Design Pattern In Swift》By Adam Freeman,一些地方做了些许修改,并将代码升级到了Swift2.0,翻译不当之处望多包涵。

    中介者模式(The Mediator Pattern)

    用一个中介者对象来封装一系列的对象交互。中介者使得各对象不需要显式地相互引用,从而使其松散耦合,而且可以独立地改变它们之间的交互。


    示例工程

    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类用来代表接近机场的一架飞机并且用Position结构体来追踪它的位置。当然机场也可能有其它的飞机在接近,所以每一个Airplane对象都会追踪其它接近的飞机,以免距离太近。然后我们看看main.swift中的应用:

    // 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()
    

    运行程序:

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

    理解中介者模式解决的问题

    当有几架飞机同时接近机场时,问题出现了。

    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))
    

    运行程序:

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

    这里只有三架飞机而已,但是main.swift中的代码已经变得十分复杂臃肿了。



    当我们再增加一架飞机的时候,就更难受了。



    理解中介者模式

    中介者模式通过引入一个中介者对象来简化两个对象或者更多对象之间的通信。为了使得对象间低耦合,中介者保持追踪所有对象的状态并且传输它们之间的通信。



    实现中介者模式

    中介者模式的核心是有一对协议:一个是定义同事对象的协议,另一个是中介者的协议。

    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中的应用:

    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))
    

    运行程序:

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

    中介者并发保护

    对中介者进行并发保护保证了同事类集合不会损坏。

    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
        }
    }
    

    我们想要能并发的去读取同事类集合的数据直到要修改它,因此用了一个并行队列并用同步的方式提交读操作。用dispatch_barrier_sync方法去获得唯一的访问来修改。


    并发保护同事类

    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")
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:行为模式-中介者模式(The Mediator Pattern)

          本文链接:https://www.haomeiwen.com/subject/wnimrttx.html