設計模式深入淺出(六)物件去耦——中介者
物件去耦
我們的程式中,一般不會只有一個類,而通常是有多個類互相合作。
既然提到互相合作,那麼類物件間的耦合性是不可避免的。但是我們需要控制耦合的程度,將類的實現及關係控制在可以靈活改變的程度。
當我們發現我們的程式碼,牽一髮而動全身的時候,有兩個可能:
1. 類封裝的不合理,不符合職責單一原則
2. 類之間的組織方式不合理,需要物件去耦。而這,就需要物件去耦模式。
物件去耦主要包括兩種模式:中介者,觀察者。
今天,我們先看中介者模式。
一個例子
試想一下,我們要實現如下的APP功能,都是如何做的?
這個APP有一個colorView,用來顯示對應的color button點選的顏色。同時,colorLabel會顯示當前選中顏色的中文名稱。並且,我們有一個Disable按鈕,它會將所有的顏色選擇按鈕禁用,並將colorView設定為cleanColor。
程式碼該怎麼寫?so easy。
//
// ViewController.m
// MediatorDemo
//
// Created by ShiTeng on 17/10/16.
// Copyright © 2017年 Eren. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIView *colorView;
@property (strong, nonatomic) IBOutlet UILabel *colorLabel;
@property (strong, nonatomic) IBOutlet UIButton *redButton;
@property (strong, nonatomic) IBOutlet UIButton *greenButton;
@property (strong, nonatomic) IBOutlet UIButton *orangeButton;
@property (strong, nonatomic) IBOutlet UIButton *yellowButton;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)redClick:(id)sender {
self.colorView.backgroundColor = [UIColor redColor];
self.colorLabel.text = @"紅色";
}
- (IBAction)greenClick:(id)sender {
self.colorView.backgroundColor = [UIColor greenColor];
self.colorLabel.text = @"綠色";
}
- (IBAction)orangeClick:(id)sender {
self.colorView.backgroundColor = [UIColor orangeColor];
self.colorLabel.text = @"橘紅色";
}
- (IBAction)yellowClick:(id)sender {
self.colorView.backgroundColor = [UIColor yellowColor];
self.colorLabel.text = @"黃色";
}
- (IBAction)disableClick:(id)sender {
self.colorView.backgroundColor = [UIColor clearColor];
self.redButton.userInteractionEnabled = NO;
self.greenButton.userInteractionEnabled = NO;
self.orangeButton.userInteractionEnabled = NO;
self.yellowButton.userInteractionEnabled = NO;
self.colorLabel.text = @"未知";
}
@end
好,讓我們思考這樣一個問題:毫無疑問,在我們的colorButton,colorView,colorLabel,disableButton之間,是有關聯的。比如,當我點選colorButton,colorView需要變色,同時colorLabel需要顯示對應的中文名字。
那麼,colorButton, colorView, colorLable之前有相互引用嗎?沒有。
從程式碼設計角度來講,很神奇是不是,幾個相互關聯的物件之間竟然沒有相互的引用。也就是說,colorButton根本不知道colorView,colorLabe的存在。colorButton只需要專注於相應click事件就好。
這是怎麼實現的呢?從程式碼裡很容易看出,我們的colorButton在接收click事件時,並沒有將事件直接通知給colorView和colorLabel,而是將click事件通知給了當前的UIViewController物件。同理,disableButton也是這麼做的。
- (IBAction)orangeClick:(id)sender {
self.colorView.backgroundColor = [UIColor orangeColor];
self.colorLabel.text = @"橘紅色";
}
- (IBAction)disableClick:(id)sender {
self.colorView.backgroundColor = [UIColor clearColor];
self.redButton.userInteractionEnabled = NO;
self.greenButton.userInteractionEnabled = NO;
self.orangeButton.userInteractionEnabled = NO;
self.yellowButton.userInteractionEnabled = NO;
self.colorLabel.text = @"未知";
}
將這種關係畫一下示意圖:
所有的物件都沒有耦合,它們僅是將自己的事件告訴UIViewController,UIViewController會呼叫對應的View來響應變化。UIIViewController在這裡充當了各個view的中介(Mediator)的作用。
OK,這就是中介者模式。中介者模式通過將所有的事件轉發到中介者上,由中介者進行訊息的轉發與呼叫相關的物件進行處理,這樣使本來相關的各個物件徹底解耦。
中介者模式
用一箇中介物件來封裝一系列的物件互動。中介者使各物件不需要顯示地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。
一般的,我們將相互作用的物件(例子中的colorButton,colorView,Label等)稱為“同事(colleague)”,而負責協調同事們共同協作的中間人(UIViewController),我們稱之為中介者(Mediator)。
UML圖為:
這裡有幾個要點:
- Mediator知道所有的Colleague物件
- Colleague物件不知道對方Colleague,它僅是將自身的事件傳到Mediator,由Mediator負責排程對應的Colleague。
優缺點
優點:
- 中介者的優點很明顯,將相關的物件之間做了徹底地解耦。
- 它使得控制更集中化
缺點:
- 中介者模式雖然將相關聯的物件徹底的解耦,但是實質上是將物件間的關聯由“物件間”轉移到“中介者”內部。這就導致中介者本身的耦合性相當高,而且會成為一個無所不知,無所不能的超級類。
如何簡化“中介者”,是中介者模式的一個難點。
相關的,iOS的元件化程式設計,也是利用了中介者模式的思想。將APP切分成若干子工程,而這些工程,則是由中介者工程所連線,協作。