android设计模式之中介者模式

中介者模式包装了一系列对象相互作用的方式,使得对象不必相互明显作用。使它们可以松散耦合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用。保证这些作用可以彼此独立变化。中介者模式将多对多的相互作用转化为一对多的相互作用。中介者模式将对象的行为和协作抽象化,把对象在小尺度的行为上与其他对象的相互作用分开处理。

android设计模式之中介者模式_第1张图片

 

Mediator:抽闲中介者角色,定义了同事对象到中介者对象的接口,一般以抽象类的方式实现。

ConcreteMediator:具体中介者角色,继承于抽象中介者,实现了父类定义的方法,它从具体的同事对象接收消息,向具体同事对象发出命令。

Colleague:抽象同事角色,定义了中介者对象的接口,它知道中介者而不知道其他同事对象。

ConcreteColeagueA/B:具体同事类角色,继承于抽象同事类,每个具体同事类都知道本身在小范围内的行为,而不知道他在大范围内的目的。

 

中介者模式简单Demo 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\Mediator.java

//抽象中介者
public abstract class Mediator {

    protected ConcreteColleagueA colleagueA;//具体同事A
    protected ConcreteColleagueB colleagueB;//具体同事B

    /**
     * 抽象中介方法、子类实现
     */
    public abstract void method();

    public void setColleagueA(ConcreteColleagueA colleagueA) {
        this.colleagueA = colleagueA;
    }

    public void setColleagueB(ConcreteColleagueB colleagueB) {
        this.colleagueB = colleagueB;
    }
}

 

//具体中介者
package mediatorpattern.gome.com.mediatordemo;

/**
 * Created by ying.zhang on 2018/8/15.
 */

public class ConcreteMediator extends Mediator {
    @Override
    public void method() {
        colleagueA.action();

        colleagueB.action();
    }
}
D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\Colleague.java

//抽象同事
public abstract class Colleague {

    protected Mediator mediator;//中介者对象

    public Colleague (Mediator mediator) {
        this.mediator = mediator;
    }

    /**
     * 同事角色的具体行为,由子类去实现
     */
    public abstract void action();
}
D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\ConcreteColleagueA.java

/**
 * Created by user on 2018/8/15.
 * 具体同事A
 */
public class ConcreteColleagueA extends Colleague {
    public ConcreteColleagueA(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void action() {
        Log.v(MainActivity.TAG, "ColleagueA 将信息递交给中介者处理");
    }
}

 

 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\ConcreteColleagueB.java

/**
 * Created by ying.zhang on 2018/8/15.
 * ConcreteColleagueB
 */

public class ConcreteColleagueB extends Colleague {

    public ConcreteColleagueB(Mediator mediator) {
        super(mediator);
    }

    @Override
    public void action() {
        Log.v(MainActivity.TAG, "ColleagueB 将想你想递交给中介者处理");
    }
}

 

中介者模式的例子很多,计算机就是一个中介者模式的例子,以计算机主机为例,计算机主机部分构成主要分为几块:CPU、内存、显卡、IO设备,一般来说一台计算机有了前两块:CPU、内存、显卡、IO设备,一般来说一台计算机有前面两块就可以运行启动了,当然,如果要连接显示器显示画面,那么还需要加上显卡,如果需要存储数据,那还需要加上IO设备,但是,在本节中这些部分都不重要,因为它们分割开来也是一个普通零部件而已,我们需要 将这些零部件整合起来,那就是主板。

package mediatorpattern.gome.com.mediatordemo;
/**
 * Created by ying.zhang on 2018/8/15.
 * 抽象中介者
 * 抽象中介者只是定义了一个抽象接口方法,具体的同事类通过该方法通知中介者自身的状态改变。
 */
public abstract class ZMeditor {

    /**
     * 同事对象改变时通知中介者的方法
     * 在同事对象改变时由中介者通知其他对象
     *
     * @param c 同事对象
     */
    public abstract void changed(ZColleague c);
}
package mediatorpattern.gome.com.mediatordemo;


/**
 * Created by ying.zhang on 2018/8/15.
 * 具体的中介者是主板,它负责联络各个同事类,也就是CPU、内存、显卡、IO设备等
 */

public class MainBoard extends ZMeditor {

    private CDDevice cdDevice;//光驱设备
    private CPU cpu;//CPU
    private SoudCard soudCard;//声卡设备
    private GraphicsCard graphicsCard;//显卡设备


    @Override
    public void changed(ZColleague c) {
        if (c == cdDevice) {
            handleCD((CDDevice) c);
        } else if (c == cpu) {
            handleCPU((CPU) c);
        }
    }

    /**
     * 处理光驱读取数据后其他设备的交互
     * @param cdDevice
     */
    private void handleCD(CDDevice cdDevice) {
        cpu.decodeData(cdDevice.read());
    }

    /**
     * 处理CPU读取数据后与其他设备的交互
     * @param cpu
     */
    private void handleCPU(CPU cpu) {
        soudCard.soudPlay(cpu.getDataSound());
        graphicsCard.videoPlay(cpu.getDataVideo());
    }

    /**
     * 设置CD设备
     * @param cdDevice
     */
    public void setCDDevice(CDDevice cdDevice) {
        this.cdDevice = cdDevice;
    }

    /**
     * 设置CPU
     *
     * @param cpu
     */
    public void setCPU(CPU cpu) {
        this.cpu = cpu;
    }

    /**
     * 设置声卡设备
     */
    public void setSoundCard(SoudCard soundCard) {
       this.soudCard = soundCard;
    }

    /**
     * 设置显卡设备
     * @param graphicsCard
     */
    public void setGraphicsCard(GraphicsCard graphicsCard) {
        this.graphicsCard = graphicsCard;
    }
}

 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\ZColleague.java


package mediatorpattern.gome.com.mediatordemo;

/**
 * Created by ying.zhang on 2018/8/15.
 * 抽象同事
 */

public abstract class ZColleague {

    protected ZMeditor mediator;//每个Colleague都应该知道中介者

    public ZColleague(ZMeditor mediator) {
        this.mediator = mediator;
    }
}

 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\CDDevice.java


package mediatorpattern.gome.com.mediatordemo;

/**
 * Created by ying.zhang on 2018/8/15.
 * CD 设备负责读取光盘的数据并将数据提供给主板
 */

public class CDDevice extends ZColleague {

    private String data;//视频数据

    public CDDevice(ZMeditor mediator) {
        super(mediator);
    }

    /**
     * 读取视频数据
     * @return  视频数据
     */
   public String read() {
        return data;
   }

    /**
     * 加载视频数据
     */
   public void load() {

       //实际情况中视频数据和音频数据是在一个数据流中的
       data = "视频数据,音频数据";
       //通知中介者,也就是主板数据改变
       mediator.changed(this);
   }
}
D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\CPU.java

package mediatorpattern.gome.com.mediatordemo;

/**
 * Created by ying.zhang on 2018/8/15.
 * 首先是CPU,其负责对主板传递过来的音、视频数据解码
 */

public class CPU extends ZColleague {

    private String dataVideo, dataSound;//视频和音频数据

    public CPU(ZMeditor mediator) {
        super(mediator);
    }

    /**
     * 获取视频数据
     *
     * @return 视频数据
     */
    public String getDataVideo() {
        return dataVideo;
    }

    /**
     * 获取音频数据
     * @return 音频数据
     */
    public String getDataSound() {
        return dataSound;
    }

    /**
     * 解码数据
     * @param data
     *
     */
    public void decodeData(String data) {

        //分割音、视频数据
        String[] tmp = data.split(",");

        //解析音、视频数据
        dataVideo = tmp[0];

        dataSound = tmp[1];

        //告诉中介者自身状态改变
        mediator.changed(this);

    }
}

 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\GraphicsCard.java


package mediatorpattern.gome.com.mediatordemo;

import android.util.Log;

/**
 * Created by ying.zhang on 2018/8/15.
 * 显卡和声卡分别用来播放视频和音频
 */

public class GraphicsCard extends ZColleague {

    public GraphicsCard(ZMeditor mediator) {
        super(mediator);
    }

    /**
     * 播放视频
     * @param data 视频数据
     */
    public void videoPlay(String data) {
        Log.v(MainActivity.TAG, "视频:" + data);
    }
}

 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\SoudCard.java


package mediatorpattern.gome.com.mediatordemo;

import android.util.Log;

/**
 * Created by ying.zhang on 2018/8/15.
 *
 */

public class SoudCard extends ZColleague {

    public SoudCard(ZMeditor mediator) {
        super(mediator);
    }


    /**
     * 播放视频
     *
     * @param data 音频数据
     */
    public void soudPlay(String data) {
        Log.v(MainActivity.TAG,"音频:" + data);
    }
}

 

D:\Users\user\AndroidStudioProjects\MediatorDemo\app\src\main\java\mediatorpattern\gome\com\mediatordemo\MainActivity.java


public class MainActivity extends AppCompatActivity {

    public static final String TAG = "Mediator_zy";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //构造主板对象
        MainBoard mainBoard = new MainBoard();

        //分别构造各个零部件
        CDDevice cd = new CDDevice(mainBoard);
        CPU cpu = new CPU(mainBoard);
        GraphicsCard graphicsCard = new GraphicsCard(mainBoard);
        SoudCard sc = new SoudCard(mainBoard);

        //将各个零部件安装到主板
        mainBoard.setCDDevice(cd);
        mainBoard.setCPU(cpu);
        mainBoard.setGraphicsCard(graphicsCard);
        mainBoard.setSoundCard(sc);

        //完成之后就可以开始播放视频了
        cd.load();

    }
}

 

 Log分析:
08-15 13:46:17.599 8088-8088/mediatorpattern.gome.com.mediatordemo V/Mediator_zy: 音频:音频数据
08-15 13:46:17.600 8088-8088/mediatorpattern.gome.com.mediatordemo V/Mediator_zy: 视频:视频数据

 android设计模式之中介者模式_第2张图片

 

中介者模式在Android源码中的一个比较好的例子是Keyguard锁屏的功能实现,查找设计模式实现的小技巧。Android源码的命名相当规范,如果要找一个设计模式,以中介者模式为例,只需要在源码中搜索“Mediator”关键字,就能够找到KeyguardViewMediator这个类,顺藤摸瓜只需阅读KeyguardViewMediator的源码就可以扎到其他的同事类,由此构建一个完整的设计模式类图。

#Android8.0
public class KeyguardViewMediator extends SystemUI {
          ... ...
    private AlarmManager mAlarmManager;
    private AudioManager mAudioManager;
    private StatusBarManager mStatusBarManager;

      /** High level access to the power manager for WakeLocks */
    private PowerManager mPM;

/**
 * Used to keep the device awake while to ensure the keyguard finishes opening before
 * we sleep.
 */
private PowerManager.WakeLock mShowKeyguardWakeLock;

private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;

... ...
}

 

我们在KeyguardViewMediator中看到很多xxxManager管理器的成员变量,这些各种各样的管理器其实就是同事类,Android使用KeyguardViewMediator来充当中介者 协调这些管理器的状态改变,同样地,KeyguardViewMediator中定义了很多方法来处理这些管理器的状态,以解锁或锁屏时声音的播放为例,在KeyguardViewMediator中对应playSounds方法来协调音频的这一状态。

 private void playSounds(boolean locked) {
        playSound(locked ? mLockSoundId : mUnlockSoundId);
    }


    private void playSound(int soundId) {
        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();
            }

            mUiOffloadThread.submit(() -> {
                // If the stream is muted, don't play the sound
                if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;

                int id = mLockSounds.play(soundId,
                        mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
                synchronized (this) {
                    mLockSoundStreamId = id;
                }
            });

        }
    }

另一个Android中关于中介者模式的例子是Binder机制,Binder机制是Android中非常重要的一个机制,其用来绑定不同的系统级服务并进行跨进程通信。在Binder机制中,有3个非常重要的组件:Servicemanager、Binder Driver和Bp Binder,其中 Bp Binder是Binder的一个代理角色,其提供IBinder接口给各个客户端服务使用,这三者就扮演了一个中介者的角色。当手机启动后,ServiceManager会先向Binder Driver进行注册,注意,这里的ServiceManager虽然是一个特殊的服务,但毕竟还是一个服务,其特殊性在于,它在Binder Driver中是最先被注册的,其注册ID为0,当其他的服务要注册到Binder Driver时,会先通过这个0号ID获取到ServiceManager所对应的IBinder接口,该接口的实质上的实现逻辑是由BpBinder实现的,获取到对应的接口后就回调其中的transcat方法,此后就会在Binder Driver中新注册一个ID 1来对应这个服务,如果有客户端想要使用这个服务,那么,它会先像Binder Driver一样获取到ID为0的接口,也就是ServiceManager所对应的接口,并调用其transcat方法要求连接到刚才的服务,这时候Binder Driver就会将ID为1的服务回传给客户端并将相关消息反馈给ServiceManager完成连接。这里的ServiceManager和Binder Driver就相当于一个中介者,协调各个服务端与客户端。

 

参考《Android源码设计模式》

 

 

 

你可能感兴趣的:(Android设计模式,移动开发,Android源码设计模式)