朋友,恭喜阿!!經過幾年的無人駕駛技術研究,我們總算有了突破,防撞系統出來了!當然了,這完全少不了Stone City市長的大力支持(不然我們真的泡麵都吃不到,只能吃土了,感謝感謝)。
那麼今天我們就來邀請Wood City, Iron City以及 Water City的夥伴一起來參與測試,一起來見證這劃時代的創新技術吧。
防撞系統測試
我們的目標是讓四台汽車可以在沒有人駕駛的情況下順利的在一條路上行駛,就像上面的圖所表示的,四台車一起從左到右邊,但出發前是不知道四輛汽車的出發順序。
我們給系統做了一個車輛距離的檢測,當兩台車距離小於5個單位的時候,會發出警報提醒。
我們定義了一個TestPosition,用來規定“距離”的格式,並且建立了TestCar。
為了能夠讓“防撞系統”運作,我們可以使用addCarsInArea()來加入觀察的對象。當自身距離改變的時候,通過
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
struct TestPosition { var x:Int } class TestCar { var carName:String var currentPosition:TestPosition private var otherCars:[TestCar] init(carName:String, position:TestPosition) { self.carName = carName self.currentPosition = position self.otherCars = [TestCar]() } // 加入關注的汽車對象 func addCarsInArea(cars:TestCar...) { for car in cars { otherCars.append(car) } } // 當有車輛改變位置時,檢查是不是太靠近了。 func checkIsOtherCarsTooClose(car:TestCar) -> Bool { return currentPosition.x - car.currentPosition.x < 5 } // 更新目前車輛的位置 func changePosition(newPosition:TestPosition) { self.currentPosition = newPosition for car in otherCars { if car.checkIsOtherCarsTooClose(car: self) { print("\(carName), 慢一點,太靠近 \(car.carName) 了") } } print("\(carName) 移動到了位置 \(currentPosition.x)") } } |
好的,讓我們來在模擬環境中測試一下,我們將四輛車都進行初始化,並且給他們一個初始化的位置,分別是0、10、20、30。
接著將他們都加入彼此的觀察名單中,當有一輛車移動的時候就會互相檢查是不是太靠近了。
最後呢,我們試著將woodTestCar從10的位置移動到17試試看。
1 2 3 4 5 6 7 8 9 10 11 12 |
let stoneTestCar = TestCar(carName: "Stone Car", position: TestPosition(x: 0)) let woodTestCar = TestCar(carName: "Wood Car", position: TestPosition(x:10)) let ironTestCar = TestCar(carName: "Iron Car", position: TestPosition(x:20)) let waterTestCar = TestCar(carName: "Water Car", position: TestPosition(x:30)) stoneTestCar.addCarsInArea(cars: woodTestCar, ironTestCar, waterTestCar) woodTestCar.addCarsInArea(cars: stoneTestCar, ironTestCar, waterTestCar) ironTestCar.addCarsInArea(cars: stoneTestCar, woodTestCar, waterTestCar) waterTestCar.addCarsInArea(cars: stoneTestCar, woodTestCar, ironTestCar) woodTestCar.changePosition(newPosition: TestPosition(x: 15)) |
結果來了,當woodTestCar移動到17的位置時,系統給除了警報,太靠近Stone Car了。
看來我們的防撞系統成功了!
1 2 |
Wood Car, 慢一點,太靠近 Stone Car 了 Wood Car 移動到了位置 15 |
不過你我都知道,如果車子越來越多,這套系統的運算會變得越來越複雜,每一輛汽車都要去觀察其他車輛的狀態。而且萬一有一輛汽車漏掉了某輛汽車的監控,那就會造成悲劇了……
所以我們需要一個更好的技術來解決這些車輛彼此之間的通信問題。
中介者模式(Mediator Pattern)
- 解決什麼問題:同類對象之間的通信問題。
- 優點:使用中介者模式之後,對象之間不需要保持聯繫,只需要通過中介者對象來交互。
- 何時不該用:如果需要讓一個對象給一組互不相關的對象發送通知時,則應該使用觀察者模式。
我們先來規範Peer以及Mediator的協議。
1 2 3 4 5 6 7 8 9 10 |
protocol Peer { var name:String {get} func checkIsOtherCarsTooClose(position:Position) -> Bool } protocol Mediator { func registerPeer(peer:Peer) func unregisterPeer(peer:Peer) func changePosition(peer:Peer, pos:Position) -> Bool } |
然後我們實現CarMediator,他將會遵循Mediator協議,這裡可以看到觀察者模式的影子。
提供了註冊、註銷的功能,並且當有車輛變動位置時,可以調用changePosition功能,來判斷註冊車輛中是否有過於靠近的車輛。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class CarMediator: 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.removeValue(forKey: peer.name) } func changePosition(peer: Peer, pos: Position) -> Bool { for storedPeer in peers.values { if peer.name != storedPeer.name && storedPeer.checkIsOtherCarsTooClose(position: pos) { return true } } return false } } |
而我們的Car需要遵循Peer協議。當汽車位置改變時,會通過changePosition()來通知mediator位置改變的情況,從而讓mediator來通知大家最新的位置情況,而不用再讓四台車互相通知了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Car: Peer { var name:String var currentPosition:Position var mediator:Mediator init(name:String, pos:Position, mediator: Mediator) { self.name = name self.currentPosition = pos self.mediator = mediator mediator.registerPeer(peer: self) } func checkIsOtherCarsTooClose(position: Position) -> Bool { return abs(position.x - self.currentPosition.x) < 5 } func changePosition(newPosition:Position) { self.currentPosition = newPosition print("\(name) 移動到了 \(self.currentPosition.x)") if(mediator.changePosition(peer: self, pos: self.currentPosition)) { print("\(name) 太靠近其他車了,慢一點)") } } } |
接下來就是測試階段。
首先我們初始化一個mediator,用來處理各車之間的通訊問題。
再來我們初始化四輛車,並且賦予它們初始位置,分別是0、10、20、30.
接著我們移動woodCar到17的位置,讓他非常靠近ironCar。
1 2 3 4 5 6 7 8 |
let mediator:Mediator = CarMediator() let stoneCar = Car(name: "Stone Car", pos: Position(x:0), mediator: mediator) let woodCar = Car(name: "Wood Car", pos: Position(x:10), mediator: mediator) let ironCar = Car(name: "Iron Car", pos: Position(x:20),mediator: mediator) let waterCar = Car(name: "Water Car", pos: Position(x:30), mediator: mediator) woodCar.changePosition(newPosition: Position(x: 17)) |
從輸出結果我們可以看到“防撞系統”正確的運行啦~!!
1 2 |
Wood Car 移動到了 17 Wood Car 太靠近其他車了,慢一點) |
太棒了,看來很快我們就能夠從方向盤上釋放我們的雙手,讓我們專心地欣賞風景了:D
iOS App開發中的例子
在iOS開發中,我們常會碰到ViewController相互之間的跳轉,比如:
- 首頁跳轉到商品列表,商品列表跳到商品詳情。
- 首頁跳到登入畫面。
- 首頁跳出廣告。
- 在商品詳情頁面跳出用戶登入介面。
- … …
當我們的項目越來越複雜的時候,這個跳轉關係就像義大利麵一樣了…所以如果我們可以引入Mediator的概念:
當有了Mediator跳轉關係一下子就變得清楚很多了,而這裡的Mediator相當於一個路由器(Router)
推薦閱讀:
- iOS應用架構談組件化方案
- 蘑菇街App的組件化之路
- 本文中提到的中介者模式的例子放在github上了。