适配器模式,这个词对于大多数人并不陌生。一说适配器模式, 很多人就想到了ListView啊, Adapter, 对,ListView与Adapter确实是适配器模式在Android中最经典的使用之一了。也有一些人可能不太清楚,会说我没用过啊,其实这个还真不一定。那么请不清楚适配器模式的小伙伴们跟随我的脚步去探索,希望到最后你能说,哦,原来是这样;对,就是这样的。
1. 官方解释
适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为
接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
2.概念理解
适配器模式解决什么问题呢 ? 或许很多人不明白,或者说知道一些,但是不甚清楚。先说一下我的理解吧。
适配器模式解决的是兼容冲突问题。通俗讲就是,我想要一个东西,但是目前手上没有,只有一个类似的。这
就是兼容冲突,我想要的,没有,只有一个不满足我条件的。
举个例子, 我现在手上有一个笔记本,系统是Windows的; 那么我现在想用这个笔记本来开发NDK,大家都
知道,C库的编译或ndk的开发是以Linux系统为佳的,那么我怎么办呢 ?答案当然是重装系统!
对重装系统来进行分析, 我现在有一个Windows系统的笔记本,但需要的是一个Linux系统的,此时需求便不兼容了,也就是冲突了。因此要重装系统。
适配器解决的问题就是重装系统, 如何把当前提供的不满足要求的资源,转化为当前需要的资源,就是这么简单~
相信对于适配器模式的概念都理解了,它的作用就在于适配,也可以称为转化。比如我们服务端返回的Json字符串,但是我们需要实体类。如果我们想要统一处理,比如如下伪代码
public class Response { // 服务端返回的封装类
String json; // 服务端返回的是json数据
}
public interface Responsable<T> {
public T getResponseBean(Class<T> cls); // 我们想要返回的是实体类, 参数为什么实体类
}
public class BeanResponse<T> extends Response implements Responsable<T> {
T getResponseBean(Class<T> cls) {
// 取出cls的变量
// 与json的字段对比,如果一致就赋值
// 得到一个对象并返回
}
}
以上这段代码就很好的契合了适配器的定义,把不满足要求的对象,转化为我们需要的对象。明白了什么是适配器模式,怎么用,现在来说下理论。
适配器模式分为3种, 分别为类适配, 对象适配, 接口适配
类适配模式
上述代码, 以继承原始类,实现目标接口实现适配的方式,称之为类适配模式
类适配模式的核心是以继承的方式来实现,也就是我们手上不满足当前要求的Windows笔记本,返回的JSON格式的数据,通过继承的方式取到。以下以一段简短的代码来说明
/**
* @author qichunjie 2018/3/14
*/
public class ClassAdapter {
public void main(String[] args) {
UserAdapter adapter = new UserAdapter();
adapter.getDescription();
}
public class User {
private String name = "小明";
private int age = 18;
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public interface Descriptor {
String getDescription();
}
public class UserAdapter extends User implements Descriptor {
@Override
public String getDescription() {
return getName() + "今年" + getAge() + "岁了。";
}
}
}
对象适配模式
如果明白了类适配,那么对象适配就再容易不过了,我跟你解释一句,保证你在不知道什么是对象适配的情况下写出来。那么关键的地方来了,我想解释什么呢?
我们已经知道,类适配是通过继承的形式来得到当前不满足条件的对象,也就是Windows系统的笔记本。对象适配则是通过传参的形式来得到当前不满足条件的对象。
以类适配的代码为例,我们想得到一个完整的描述,但是目前只有Name和Age。
类适配 : 继承User得到Name和Age
对象适配: 传入User对象,来得到Name和Age
对象适配模式的代码如下:
public class ClassAdapter {
public void main(String[] args) {
UserAdapter adapter = new UserAdapter();
adapter.getDescription();
}
public class User {
private String name = "小明";
private int age = 18;
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public interface Descriptor {
String getDescription();
}
public class UserAdapter implements Descriptor {
private User user;
public UserAdapter(User user) {
this.user = user;
}
@Override
public String getDescription() {
return user.getName() + "今年" + user.getAge() + "岁了。";
}
}
}
不再继承,直接传入已知不满足条件的对象,就是这么简单。
接口适配模式
类与对象适配的区别在于类信息的来源不同,一个是继承, 一个是传参。 接口适配模式中,这个不满足条件的已知对象,不是一个类了,而是接口。
相信很多人都用过动画, 很多时候我们需要在动画结束的时候执行一些逻辑,比如启动页面动画完毕之后跳转到主页面啊, 比如动画A完了之后,控件B要显示出来等。我们往往做的一件事肯定就是监听动画的执行,
如下:
Animator animator = ...; // 此处实例一个对象
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
宝宝觉得很委屈啊, 明明只需要一个onAnimationEnd(), 现在却不得不实现其他的3个方法,得不偿失啊有木有。对我这种对冗余厌烦到骨子里的人,真真是受不了的。
针对这种情况,我们常做的一个方法就是来一个类AnimatorImpl实现这个接口,方法体保持为空。为什么呢?因为无论是接口,还是抽象类的抽象方法,都是必须要实现所有方法的。 但是一个普通类就不用了,我们不实现这些方法, 在使用的时候,需要哪个方法,重写哪个方法即可。我相信有人这么用过,或许他还不明白,这就是接口适配器模式...
接口适配器:通过实现已知的不满足条件的接口, 来确保只得到我们需要的方法。
我们拥有的对象: 一个包含N个方法的接口, N > 1
我们需要的对象: N个方法中的一个或几个 , 少于N个
我们需要如何做: 通过类实现接口, 想重写几个几个方法,就重写几个方法
代码如下:
public class AnimatorImpl implements Animator.AnimatorListener {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
}
public void main(String[] args) {
Animator animator = null;
animator.addListener(new AnimatorImpl(){
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
}
怎么样,是不是很简单呢 ? 应用场景也很好理解。