设计模式是一套被反复使用,多数人知晓,经过分类编目的,代码设计的总结,也可以说是前人的智慧结晶。学习设计模式能让我们对一些应用场景使用相同的套路达到很好的效果,我会不定时更新一些自己
对设计模式的理解的文章,从定义,实现,应用场景来说说设计模式,今天我要说的对象是适配器模式
一:定义
适配器模式也被称为不协调的兼容模式,当想调用某个接口,但有发现这个接口不能被直接调用,需要一个中间类来处理的时候,适配器模式就出现了,而这个中间类也被称为适配器类,
它的定义是这样的:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
适配器模式的结构图如下
可以看出适配器模式组成成员有4个,他们的介绍如下
1.客户端类(Client):需要调用某个接口的类,它是具体的使用者
2.目标类(Target):它是被调用的抽象,一般定义了一个抽象的方法,它可以是抽象类或者接口
3.适配器类(Adapter):适配器模式的核心,实现Target中的抽象方法,并且调用需要被适配(不能直接调用)类的方法
4.适配者类(Adaptee):含有一个需要被调用的方法,但这个方法不能被客户端直接调用,需要适配器适配,相当于做一个兼容处理
二:实现
适配器模式根据实现的不同可以分为对象适配器,类适配器,缺省适配器
假设我们现在遇到一种这样的情形,我们的类库里面有 一个针对int进行排序的算法,但是现在有一家公司需要对他们的一笔账单进行排序,账单都是含有
两位小数的double类型,很显然类库已有的int排序方法,不能直接用于对这笔账单进行排序,我们需要做一个适配器
1.对象适配器
对象适配器的核心就是在这个适配器中会引入一个适配者类的成员变量
/**
* 适配者类,有一个给int类型排序的方法
*/
class SortAdaptee{
/**
* 一个简单的冒泡排序算法
* @param numbers
*/
public void bubbleSort(int[] numbers) {
int temp = 0;
int size = numbers.length;
for(int i = 0 ; i < size-1; i ++) {
for(int j = 0 ;j < size-1-i ; j++) {
if(numbers[j] > numbers[j+1]){//交换两数位置
temp = numbers[j];
numbers[j] = numbers[j+1];
numbers[j+1] = temp;
}
}
}
}
}
/**
* 适配器类
*/
class SortAdapter{
private SortAdaptee sortAdaptee=new SortAdaptee();
public double[] bubbleSort(double[] numbers){
int[] ints=doubleToInt(numbers);
sortAdaptee.bubbleSort(ints);
return intToDouble(ints);
}
/**
* 将double数组转换成int数组,double转int肯定会丢失精度,这里假设客户要求保留2位小数
* @param numbers
* @return
*/
private static int[] doubleToInt(double[] numbers){
int[] its=new int[numbers.length];
for(int i=0;i<numbers.length;i++){
its[i]=(int)(numbers[i]*100);//先放大100倍,然后再缩小,就达到了保存2位小数的目的
}
return its;
}
/**
* 将int数组转换成double数组
* @param numbers
* @return
*/
private static double[] intToDouble(int[] numbers){
double[] doubles=new double[numbers.length];
for(int i=0;i<numbers.length;i++){
doubles[i]=(double)(numbers[i])/100;//缩小
}
return doubles;
}
}
class Test{
public static void main(String[] dfd){
double[] moneys=new double[]{23.22,17.98,88.99,65.33,5.88,8.53};
moneys=new SortAdapter().bubbleSort(moneys);
System.out.println("这是排序后的数据:");
for (double money:moneys){
System.out.println(money);
}
}
}
这是打印的结果:
这是排序后的数据:
5.88
8.52
17.98
23.22
65.33
88.99
2.类适配器
类适配器实际上是运用继承,适配器类继承适配者类,在适配方法中直接调用父类的方法,在上面代码的基础之上更改如下
/**
* 适配者类,有一个给int类型排序的方法
*/
class SortAdaptee{
/**
* 一个简单的冒泡排序算法
* @param numbers
*/
public void bubbleSort(int[] numbers) {
int temp = 0;
int size = numbers.length;
for(int i = 0 ; i < size-1; i ++) {
for(int j = 0 ;j < size-1-i ; j++) {
if(numbers[j] > numbers[j+1]){//交换两数位置
temp = numbers[j];
numbers[j] = numbers[j+1];
numbers[j+1] = temp;
}
}
}
}
}
/**
* 适配器类
*/
class SortAdapter extends SortAdaptee{
public double[] bubbleSort(double[] numbers){
int[] ints=doubleToInt(numbers);
super.bubbleSort(ints);
return intToDouble(ints);
}
/**
* 将double数组转换成int数组,double转int肯定会丢失精度,这里假设客户要求保留2位小数
* @param numbers
* @return
*/
private static int[] doubleToInt(double[] numbers){
int[] its=new int[numbers.length];
for(int i=0;i<numbers.length;i++){
its[i]=(int)(numbers[i]*100);//先放大100倍,然后再缩小,就达到了保存2位小数的目的
}
return its;
}
/**
* 将int数组转换成double数组
* @param numbers
* @return
*/
private static double[] intToDouble(int[] numbers){
double[] doubles=new double[numbers.length];
for(int i=0;i<numbers.length;i++){
doubles[i]=(double)(numbers[i])/100;//缩小
}
return doubles;
}
}
class Test{
public static void main(String[] dfd){
double[] moneys=new double[]{23.22,17.98,88.99,65.33,5.88,8.53};
moneys=new SortAdapter().bubbleSort(moneys);
System.out.println("这是排序后的数据:");
for (double money:moneys){
System.out.println(money);
}
}
}
这是打印的结果:
这是排序后的数据:
5.88
8.52
17.98
23.22
65.33
88.99
3.缺省适配器
设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的
所有方法的情况,又称为单接口适配器模式。这种实现方式较为简单,我这里就不实现了
三:应用场景
(1) 系统需要使用一些现有的类或者接口,而这些类或者接口(如方法名)不符合系统的需要,甚至没有这些类的源代
(2) 想创建一个可以重复使用的类或者接口,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作