Java设计模式设计模式

《设计模式》适配器模式

2019-08-25  本文已影响2人  敏捷Studio

基本介绍

定义

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

介绍

适配器示例

UML类图

对象的适配器模式UML类图

角色说明:

具体实现(对象适配器模式)

首先来说下对象适配器模式的实现方式,就以电压转换为例子。

1、创建适配器接口。现在我们需要定义一个220V转换成5V的接口:

// 适配器类
interface Adapter {
  // 装换成5V
  int convert_5v();
}

2、创建被适配角色。被适配角色,一般是已存在的类,需要适配新的接口。生活中的220V电源无处不在:

// 电源
public class Electric {
  // 输出220V
  public int output_220v() {
    return 220;
  }
}

3、创建具体适配器。我们需要一个具体适配器,这个适配器就是变压器,能够将220V转为5V输出:

// 手机适配器类
public class PhoneAdapter implements Adapter {
  // 适配器持有源目标对象
  private Electric mElectric;

  // 通过构造方法传入对象
  public PhoneAdapter(Electric electric) {
    mElectric = electric;
  }

  @Override
  public int convert_5v() {
    System.out.println("适配器开始工作:");
    System.out.println("输入电压:" + mElectric.output_220v());
    System.out.println("输出电压:" + 5);
    return 5;
  }
}

4、客户端测试:

public void test() {
  Electric electric = new Electric();
  System.out.println("默认电压:" + electric.output_220v());

  // 传递一个对象给适配器
  Adapter phoneAdapter = new PhoneAdapter(electric);
  System.out.println("适配转换后的电压:" + phoneAdapter.convert_5v());
}

输出结果:

默认电压:220
适配器开始工作:
输入电压:220
输出电压:5
适配转换后的电压:5

5、说明:
上面的例子就是对象适配器模式,适配的源目标对象需要传递给适配器。

具体实现(类适配器模式)

类适配器只要是通过继承源目标类来实现

1、创建适配器接口。跟4.1一样

// 适配器类
interface Adapter {
  // 装换成5V
  int convert_5v();
}

2、创建被适配角色。跟4.2一样

// 电源
public class Electric {
  // 输出220V
  public int output_220v() {
    return 220;
  }
}

3、创建具体适配器。跟4.3有区别

// 通过继承源目标类的方式,不持有源目标对象
public class PhoneAdapter extends Electric implements Adapter {
  @Override
  public int convert_5v() {
    System.out.println("适配器开始工作:");
    System.out.println("输入电压:" + output_220v());
    System.out.println("输出电压:" + 5);
    return 5;
  }
}

4、客户端测试。跟4.4有区别

public void test() {
  Adapter phoneAdapter = new PhoneAdapter();
  System.out.println("适配转换后的电压:" + phoneAdapter.convert_5v());
}

输出结果:

适配器开始工作:
输入电压:220
输出电压:5
适配转换后的电压:5

5、说明:
类适配器模式只要通过继承源目标类来实现,无需持有源目标对象。

6、对象适配器模式与类适配器模式比较

总的来说,使用对象适配器比较好。当然具体问题具体分析。

模式总结

应用场景

优点

缺点

Android中的源码分析

说到适配器,ListViewRecyclerView就再熟悉不过了,ListView现在应该很少用了吧,这里就以RecyclerView来分析。

1、RecyclerView的使用。先来一个RecyclerView的简单使用例子:

Activity布局文件 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
 <android.support.v7.widget.RecyclerView
    android:id="@+id/rv_main_test"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical"/>
</LinearLayout>

Item 布局文件 item_rv.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="40dp">
  <TextView
    android:id="@+id/tv_item"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:text="item"/>
</LinearLayout>

Activity代码

public class MainActivity extends Activity {
  private RecyclerView mRecyclerView;
  private RecyclerView.Adapter mAdapter;
  private RecyclerView.LayoutManager mLayoutManager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initVar();
    initView();
  }  

  private void initVar() {
    mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    mAdapter = new MyAdapter(getData());
  }

  private void initView() {
    mRecyclerView = findViewById(R.id.rv_main_test);
    // 设置布局管理器
    mRecyclerView.setLayoutManager(mLayoutManager);
    // 设置adapter
    mRecyclerView.setAdapter(mAdapter);
  }

  // 获取要展示的数据
  private ArrayList<String> getData() {
    ArrayList<String> data = new ArrayList<>();
    String temp = " item";
    for (int i = 0; i < 20; i++) {
        data.add(i + temp);
    }

    return data;
  }
}

Adapter代码

// 继承RecyclerView.Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
  private ArrayList<String> mData;

  public MyAdapter(ArrayList<String> data) {
    // 初始化数据
    this.mData = data;
  }

  @Override
  // 创建一个我们自定义的ViewHolder
  public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    // 实例化要展示的view布局
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv, parent, false);
    // 实例化viewholder
    ViewHolder viewHolder = new ViewHolder(v);
    return viewHolder;
  }

  @Override
  // 绑定ViewHolder
  public void onBindViewHolder(ViewHolder holder, int position) {
    // ViewHolder中的view与数据进行绑定
    holder.mTv.setText(mData.get(position));
  }

  @Override
  // Item数量
  public int getItemCount() {
    return mData == null ? 0 : mData.size();
  }

  public static class ViewHolder extends RecyclerView.ViewHolder {
    TextView mTv;

    // 根据实际需求,持有不同的对象。
    public ViewHolder(View itemView) {
      super(itemView);
      mTv = itemView.findViewById(R.id.tv_item);
    }
  }
}

从上面的例子可以看到,使用RecyclerView时我们要传递一个Adapter进去,然后通过复写Adapter中的onCreateViewHolder()onBindViewHolder()getItemCount()等方法以及内部类ViewHolder。通过不同的Adapter,我们能够实现不同的布局。

2、总结
上面的MyAdapter是继承RecyclerView.Adapter这个类的,而Adapter实际上是RecyclerView的内部类。这里的Adapter就充当了适配器接口,即目标角色,RecyclerView内部通过Adapter获取它需要的接口和数据等。至于MyAdapter,就是具体的适配器,通过它把不同的布局跟RecyclerView联系起来。最后就是被适配角色,即源角色,这里就是各种不同的item布局。

为什么Android要这么设计呢,想想在一个列表中,我们要展示的布局可能是简单的,也可能是超复杂的,这个布局是未知的,是根据要展示的数据集来决定的;通过适配器模式,就能够把不同的东西都可以转化成同样的接口,系统处理起来就有套路了,同时也无需关心各种千变万化的布局。

上一篇下一篇

猜你喜欢

热点阅读