适配器(Adapter)
[TOC]
定义
适配器模式对于我们安卓开发者而言其实已经是一个经常在使用的一种设计模式了,严格意义上来讲也不能说是使用,而是在这样的一个模式下开发对应的场景或者是页面了~常使用的ListView和RecyclerView就是这样的方式,为什么这么说呢?看一下适配器的定义
Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.(将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。)
我们的ViewGroup即ListView和RecyclerView都已经完成了作为一个容器布局该做的,做好了测量和布局,剩下的将childView填充到容器中则是交给了adapter,通过开发者去定义adapter,然后调用抽象的adapter获取对应的childView,最后完成整个View的渲染
简单场景使用
举个栗子,这里还是老联盟了~
想象一下把PC网友与改为手机上的端游,我们不可能从0到1复刻一个新的LOL,经过很多版本的迭代,我们要在现有的基础上去开发这个端游,那么就要尽可能的节省工作量,把更多的时间留在策划和设计上,英雄的技能和模型只需要稍作调整即可。那么我们就可以上我们的适配器模式,这里文字描述感觉还不是特别清晰,大家可以参考下面的图
A和B是无法直接连接到一起的,所以就会有C来作为适配器来把A和B连接到一起,那么这时候C就是咱们的适配器,将源A适配到咱们的目标B上面
- 适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定他们就成
- 增加了类的透明性,访问Target目标角色,但是具体的实现都委托给了源角色,而这些对高层次模块是透明的,也是它不需要关心的
- 提高了类的复用度,源角色在原有的系统中还是可以正常使用,而在目标角色中也可以充当新的演员
coding
LOL毕竟也是一个相当庞大的网游,咱们就单轮控制英雄这个角度来做这个适配器模式的场景。
首先需要一个完备的操作场景,在PC上操作英雄,那么系统需要接受鼠标和键盘发送过来的指令
首先构建一个简单的英雄移动场景
package design.adapter;
public class OperateHeroSys implements IOperateHero {
@Override
public void onMove(int x, int y) {
System.out.println("英雄移动到坐标x:" + x + ",y:" + y);
}
}
public interface IOperateHero {
/**
* 移动英雄
*
* @param x 坐标
* @param y 坐标
*/
void onMove(int x, int y);
}
接下来是PC移动英雄的例子,可见我们对英雄系统的依赖采用依赖倒置原则和里氏替换原则
public class PCOperate {
private int mX;
private int mY;
private IOperateHero mOperateHero;
public PCOperate(IOperateHero operateHero) {
mOperateHero = operateHero;
}
public void move(int x, int y) {
mX = x;
mY = y;
clickMove();
}
private void clickMove() {
if (mOperateHero != null) {
mOperateHero.onMove(mX, mY);
}
}
}
public static void main(String[] args) {
IOperateHero operateHero = new OperateHeroSys();
PCOperate pcOperate = new PCOperate(operateHero);
pcOperate.move(0, 0);
pcOperate.move(10, 10);
pcOperate.move(20, 10);
}
//英雄移动到坐标x:0,y:0
//英雄移动到坐标x:10,y:10
//英雄移动到坐标x:20,y:10
接下来我们实现移动端的操作英雄:
public class MobileOperate {
private IOperateHero mOperateHero;
private int mCurX = 0;
private int mCurY = 0;
private int mSpeed = 1;
public MobileOperate(IOperateHero operateHero) {
this.mOperateHero = operateHero;
}
public void turnLeft() {
mCurX = mCurX - mSpeed;
mCurY = mCurY;
moving();
}
public void turnRight() {
mCurX = mCurX + mSpeed;
mCurY = mCurY;
moving();
}
public void turnDown() {
mCurX = mCurX;
mCurY = mCurY + mSpeed;
moving();
}
public void turnUp() {
mCurX = mCurX;
mCurY = mCurY - mSpeed;
moving();
}
private void moving() {
if (mCurY < 0) {
mCurY = 0;
}
if (mCurX < 0) {
mCurX = 0;
}
if (mOperateHero != null) {
mOperateHero.onMove(mCurX, mCurY);
}
}
}
public class AdapterMain {
public static void main(String[] args) {
IOperateHero operateHero = new OperateHeroSys();
MobileOperate mobileOperate = new MobileOperate(operateHero);
mobileOperate.turnUp();
mobileOperate.turnUp();
mobileOperate.turnUp();
mobileOperate.turnRight();
mobileOperate.turnRight();
mobileOperate.turnRight();
mobileOperate.turnLeft();
mobileOperate.turnLeft();
mobileOperate.turnDown();
}
}
//英雄移动到坐标x:0,y:0
//英雄移动到坐标x:0,y:0
//英雄移动到坐标x:0,y:0
//英雄移动到坐标x:1,y:0
//英雄移动到坐标x:2,y:0
//英雄移动到坐标x:3,y:0
//英雄移动到坐标x:2,y:0
//英雄移动到坐标x:1,y:0
//英雄移动到坐标x:1,y:1
感觉这个例子描述的比较牵强~后期补一个在Android源码中的应用吧