Andorid设计模式Java

JAVA / Android 设计模式之适配器(Adapter)

2019-02-16  本文已影响15人  萨达哈鲁酱

简介

定义

适配器模式,即定义一个包装类,用于包装不兼容接口的对象

主要作用

把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作。

解决的问题

原本由于接口不兼容而不能一起工作的那些类可以在一起工作。


模式原理

类的适配器模式

类的适配器模式是把适配的类的API转换成为目标类的API。

UML 类图 和 组成
这里写图片描述

在上图中可以看出:

Adapter与Adaptee是继承关系,这决定了这个适配器模式是类的

对象的适配器模式

与类的适配器模式相同,对象的适配器模式也是把适配的类的API转换成为目标类的API。

UML 类图 和 组成
这里写图片描述

在上图中可以看出:

Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。


适配器模式的使用

类适配器模式的使用

步骤1:创建Target接口

public interface Target {

    //这是源类Adapteee没有的方法
    public void Request(); 
}

步骤2: 创建源类(Adaptee)

public class Adaptee {

    public void SpecificRequest(){
    }
}

步骤3: 创建适配器类(Adapter)

//适配器Adapter继承自Adaptee,同时又实现了目标(Target)接口。
public class Adapter extends Adaptee implements Target {

    //目标接口要求调用Request()这个方法名,但源类Adaptee没有方法Request()
    //因此适配器补充上这个方法名
    //但实际上Request()只是调用源类Adaptee的SpecificRequest()方法的内容
    //所以适配器只是将SpecificRequest()方法作了一层封装,封装成Target可以调用的Request()而已
    @Override
    public void Request() {
        this.SpecificRequest();
    }

}

步骤4: 定义具体使用目标类,并通过Adapter类调用所需要的方法从而实现目标

public class AdapterPattern {

    public static void main(String[] args){

        Target mAdapter = new Adapter();
        mAdapter.Request();

    }
}

对象适配器模式的使用

步骤1:创建Target接口

public interface Target {

    //这是源类Adaptee没有的方法
    public void Request(); 
}

步骤2: 创建源类(Adaptee)

public class Adaptee {

    public void SpecificRequest(){
    }
}

步骤3: 创建适配器类(Adapter)(不适用继承而是委派)

class Adapter implements Target{  
    // 直接关联被适配类  
    private Adaptee adaptee;  

    // 可以通过构造函数传入具体需要适配的被适配类对象  
    public Adapter (Adaptee adaptee) {  
        this.adaptee = adaptee;  
    }  

    @Override
    public void Request() {  
        // 这里是使用委托的方式完成特殊功能  
        this.adaptee.SpecificRequest();  
    }  
}  

步骤4: 定义具体使用目标类,并通过Adapter类调用所需要的方法从而实现目标

public class AdapterPattern {
    public static void main(String[] args){
        //需要先创建一个被适配类的对象作为参数  
        Target mAdapter = new Adapter(new Adaptee());
        mAdapter.Request();

    }
}

例子

实现步骤

步骤1: 创建Target接口(期待得到的插头):能输出110V(将220V转换成110V)

public interface Target {

    //将220V转换输出110V(原有插头(Adaptee)没有的)
    public void Convert_110v();
}

步骤2: 创建源类(原有的插头)

class PowerPort220V{
//原有插头只能输出220V
    public void Output_220v(){
    }
}

步骤3: 创建适配器类(Adapter)

class Adapter220V extends PowerPort220V implements Target{
   //期待的插头要求调用Convert_110v(),但原有插头没有
    //因此适配器补充上这个方法名
    //但实际上Convert_110v()只是调用原有插头的Output_220v()方法的内容
    //所以适配器只是将Output_220v()作了一层封装,封装成Target可以调用的Convert_110v()而已

    @Override
    public void Convert_110v(){
      this.Output_220v;
    }
}

步骤4: 定义具体使用目标类,并通过Adapter类调用所需要的方法从而实现目标(不需要通过原有插头)

//进口机器类
class ImportedMachine {

    @Override
    public void Work() {
        System.out.println("进口机器正常运行");
    }
}


//通过Adapter类从而调用所需要的方法
public class AdapterPattern {
    public static void main(String[] args){

        Target mAdapter220V = new Adapter220V();
        ImportedMachine mImportedMachine = new ImportedMachine();

        //用户拿着进口机器插上适配器(调用Convert_110v()方法)
        //再将适配器插上原有插头(Convert_110v()方法内部调用Output_220v()方法输出220V)
        //适配器只是个外壳,对外提供110V,但本质还是220V进行供电
        mAdapter220V.Convert_110v();
        mImportedMachine.Work();
    }
}

Android 中的适配器模式


// 代码省略
 ListView myListView = (ListView)findViewById(listview_id);
 // 设置适配器
 myListView.setAdapter(new MyAdapter(context, myDatas));
 
// 适配器
public class MyAdapter extends BaseAdapter{
 
        private LayoutInflater mInflater;
        List<String> mDatas ; 
 
        public MyAdapter(Context context, List<String> datas){
            this.mInflater = LayoutInflater.from(context);
            mDatas = datas ;
        }
        @Override
        public int getCount() {
            return mDatas.size();
        }
 
        @Override
        public String getItem(int pos) {
            return mDatas.get(pos);
        }
 
        @Override
        public long getItemId(int pos) {
            return pos;
        }
 
        // 解析、设置、缓存convertView以及相关内容
        @Override
        public View getView(int position, View convertView, ViewGroup parent) { 
            ViewHolder holder = null;
            // Item View的复用
            if (convertView == null) {
                holder = new ViewHolder();  
                convertView = mInflater.inflate(R.layout.my_listview_item, null);
                // 获取title
                holder.title = (TextView)convertView.findViewById(R.id.title);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder)convertView.getTag();
            }
            holder.title.setText(mDatas.get(position));
            return convertView;
        }
 
    }

因为ListView需要能够显示各式各样的视图,每个人需要的显示效果各不相同,显示的数据类型、数量等也千变万化。

为了能够进行统一,将ListView需要的接口抽象到Adapter对象中,这样只要用户实现了Adapter的接口,它使用的就是对象适配器模式,我们只需要将数据源委托给Adapter,Adapter按照目标接口对数据源进行处理,并且提供给ListView,这样ListView就可以按照用户设定的显示效果、数量、数据来显示特定的Item View。

在上面的例子中,我们可以

因为数据源的千变万化导致对ListView的适配困难,现在通过Adapter对数据源的统一适配处理,这样我们的ListView就可以按照固定的规范访问Adapter就可以了,因为Adapter是统一的,都是实现自BaseAdapter。


优缺点

适配器模式

优点
缺点

类的适配器模式

优点
缺点

对象的适配器模式

优点
缺点

总结

适配器的使用场景

类和对象适配器模式的使用场景

1: 灵活使用时:选择对象的适配器模式

2: 需要同时配源类和其子类:选择对象的适配器

3: 需要重新定义Adaptee的部分行为:选择类适配器

4: 仅仅希望使用方便时:选择类适配器

上一篇 下一篇

猜你喜欢

热点阅读