中介者模式
定义:
中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使它们可以松散耦合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。中介者模式将多对多的相互作用转化为一对多的相互作用。中介者模式将对象的行为和协作抽象化。
使用场景
当对象之间的交互操作很多且每个对象的行为操作都依赖彼此时,为防止在修改一个对象的行为时,同时涉及很多其他对象的行为,可使用中介者模式。中介者对象将系统从网状结构变成以调停者为中心的星型结构,达到降低系统的复杂性,提高可扩展性的作用
中介者模式的写法
UML图如下:
- Mediator:抽象中介者,定义了同时对象到中介者对象的接口
- ConcreteMediator:具体中介者,继承抽象中介者,实现了父类定义方法,它从具体的同事对象接收消息,向具体的同事对象发出命令
- Colleague:抽象同事类,定义了中介者对象的接口,它只知道中介者而不知道其他的同事对象
- ConcreteColleagueA/B:具体同事类,继承于抽象同事类,每个具体的同事类都知道本身在小范围的行为,而不知道它在大范围的目的
我们以电脑为例,电脑主机部分分为:CPU、内存、显卡、IO设备,他们之间存在通信关系,这是主板就是起了中介者的作用,连接各个部分
定义抽象同事:
public abstract class Colleague {
protected Mediator mediator; //每一个同事都应该知道中介者
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
}
创建具体同事:
//创建CPU
public class CPU extends Colleague {
//表示视频和音频数据
private String dataVideo,dataSound;
public CPU(Mediator mediator) {
super(mediator);
}
/**
* 获取视频数据
* @return 视频数据
*/
public String getDataVideo() {
return dataVideo;
}
/**
* 获取音频数据
* @return 音频数据
*/
public String getDataSound() {
return dataSound;
}
public void decodeData(String data) {
String[] tem = data.split(",");
//解析视频
dataVideo = tem[0];
//解析音频
dataSound = tem[1];
//通知中介者自身状态的改变
mediator.changed(this);
}
}
//创建CD设备
public class CDDevice extends Colleague {
private String data; //视频数据
public CDDevice(Mediator mediator) {
super(mediator);
}
/**
* 读取视频数据
* @return
*/
public String read() {
return data;
}
public void load() {
//实际情况中视频数据和音频数据都是在一个数据流中
data = "视频数据,音频数据";
//通知中介者,也就是主板数据改变
mediator.changed(this);
}
}
//显卡
public class GraphicsCard extends Colleague {
public GraphicsCard(Mediator mediator) {
super(mediator);
}
/**
* 播放视频
* @param data
*/
public void videoPlay(String data) {
Log.e("视频",data);
}
}
//声卡
public class SoundCard extends Colleague {
public SoundCard(Mediator mediator) {
super(mediator);
}
public void soundPlay(String data) {
Log.e("音频",data);
}
}
定义抽象中介者:
public abstract class Mediator {
/**
* 同时对象改变的时候通知中介者的方法
* 在同事对象改变时由中介者去通知其他的同事对象
* @param c 同事对象
*/
public abstract void changed(Colleague c);
}
创建具体中介者:
//主板
public class MainBoard extends Mediator {
private CDDevice cdDevice; //光驱设备
private CPU cpu; //CPU
private SoundCard soundCard; //声卡设备
private GraphicsCard graphicsCard; //显卡设备
@Override
public void changed(Colleague c) {
//若是光驱读取了数据
if (c == cdDevice) {
handleCD((CDDevice)c);
} else if (c == cpu) {
//若是CPU处理完数据
handleCPU((CPU)c);
}
}
/**
* 处理CPU读取数据后与其他设备的交互
* @param c CPU
*/
private void handleCPU(CPU c) {
soundCard.soundPlay(c.getDataSound());
graphicsCard.videoPlay(c.getDataVideo());
}
/**
* 处理光驱读取数据之后与其他设备的交互
* @param cdDevice 光驱设备
*/
private void handleCD(CDDevice cdDevice) {
cpu.decodeData(cdDevice.read());
}
/**
* 设置CD设备
* @param cdDevice
*/
public void setCdDevice(CDDevice cdDevice) {
this.cdDevice = cdDevice;
}
/**
* 设置CPU
* @param cpu
*/
public void setCpu(CPU cpu) {
this.cpu = cpu;
}
/**
* 设置声卡
* @param soundCard
*/
public void setSoundCard(SoundCard soundCard) {
this.soundCard = soundCard;
}
/**
* 设置显卡
* @param graphicsCard
*/
public void setGraphicsCard(GraphicsCard graphicsCard) {
this.graphicsCard = graphicsCard;
}
}
客户端调用:
public class Client {
public static void main(String[] args) {
//构造主板对象
MainBoard mainBoard = new MainBoard();
//分别构造各个零部件
CDDevice cd = new CDDevice(mainBoard);
CPU cpu = new CPU(mainBoard);
GraphicsCard graphicsCard = new GraphicsCard(mainBoard);
SoundCard soundCard = new SoundCard(mainBoard);
//各个零部件安装到主板
mainBoard.setCdDevice(cd);
mainBoard.setCpu(cpu);
mainBoard.setGraphicsCard(graphicsCard);
mainBoard.setSoundCard(soundCard);
//完成之后可以开始播放
cd.load();
}
}
上述是中介者模式的基本用法,但是在很多情况下,我们并不是按照中介者模式的框架来实现,大多数的情况下是直接让Activity来充当一个中介者并在其中处理相关逻辑,比方说在多UI控件交互的情境下,不同的UI状态涉及到其他UI的状态等
锁屏功能
Android中的锁屏功能就用到了中介者模式,KeyguardService(锁屏服务)通过KeyguardViewMediator(锁屏中介者)来协调各种Manager的状态以达到锁屏的功能。这里KeyguardService和各种Manager等等都充当了同事的角色
KeyguardService:
public class KeyguardService extends Service {//锁屏服务,同事角色
private KeyguardViewMediator mKeyguardViewMediator;//锁屏中介者
@Override
public void onCreate() {
((SystemUIApplication) getApplication()).startServicesIfNeeded();
//初始化中介者
mKeyguardViewMediator = ((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);
}
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
@Override // Binder interface
public void addStateMonitorCallback(IKeyguardStateCallback callback) {
checkPermission();
mKeyguardViewMediator.addStateMonitorCallback(callback);//调用中介者的接口
}
@Override // Binder interface
public void verifyUnlock(IKeyguardExitCallback callback) {
checkPermission();
mKeyguardViewMediator.verifyUnlock(callback);//调用中介者的接口
}
//其他代码略
};
}
KeyguardViewMediator:
/**
KeyguardViewMediator中通过playSound方法能够协调AudioManager去控制声音的播放等等,其他Manager同理
*/
public class KeyguardViewMediator extends SystemUI {//锁屏中介者
//各种Manager
private AlarmManager mAlarmManager;
private AudioManager mAudioManager;
private StatusBarManager mStatusBarManager;
private PowerManager mPM;
private IWindowManager mWM;
private TrustManager mTrustManager;
private SearchManager mSearchManager;
private PowerManager.WakeLock mShowKeyguardWakeLock;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
//其他代码略
private void playSound(int soundId) {//通过AudioManager去播放声音
if (soundId == 0) return;
final ContentResolver cr = mContext.getContentResolver();
if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) {
mLockSounds.stop(mLockSoundStreamId);
// Init mAudioManager
if (mAudioManager == null) {
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
if (mAudioManager == null) return;
mUiSoundsStreamType = mAudioManager.getUiSoundsStreamType();
}
// If the stream is muted, don't play the sound
if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;
mLockSoundStreamId = mLockSounds.play(soundId,
mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
}
}
}
https://www.jianshu.com/p/9b50004446dd
Android源码设计模式解析与实战