用一个设计模式培养高复用、低耦合思想
- 前言
- Android中的装饰者
- 代码实现
- 第一步:创建装饰器DecorateAdapter
- 第二步:处理头部、中间内容、尾部的绑定关系
- 第三步:装饰器的使用
- 第四步:改进、直接封装一个View出来
- 总结
前言
一个高复用、低耦合的代码不会让你在第一次去实现代码的时候感到舒服
但是他会在你后面做扩展、和同类需求的时候,直呼真香!!!
最近写需求,借用到装饰者思想做了RecyclerView的头和尾的扩展
感觉很不错,赶紧拿出来说一说,嘻嘻
ps:本篇文章只是帮助大家,在实现需求的过程中也能潜移默化的使用设计模式来优化代码
Android中的装饰者
首先一句话总结装饰者:就是不通过继承的方式,来扩展某个对象的功能,达到我们想要实现的效果。
举两个小例子,不细说,因为前面已经讲过装饰者模式相关的内容
- InputStream装饰者
InputStream装饰者:在Android中,我们经常需要读取文件或者网络流。InputStream是用于读取字节流的抽象类,而Android提供了许多装饰者类来扩展InputStream的功能。
例如,BufferedInputStream和DataInputStream都是InputStream的装饰者类,它们添加了缓冲和数据类型转换的功能。
FileInputStream fileInputStream = new FileInputStream("example.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
- View装饰者
Android中的UI组件都继承自View类,而Android提供了装饰者类来扩展View的功能
例如,可以使用LayoutInflater来给布局文件添加一些额外的装饰
LayoutInflater inflater = LayoutInflater.from(context);
View originalView = inflater.inflate(R.layout.original_layout, parentLayout, false);
ViewDecorator viewDecorator = new ViewDecorator(originalView);
View decoratedView = viewDecorator.decorate();
parentLayout.addView(decoratedView);
基于这种思想,在做RecyclerView的头和尾的扩展想到了,利用这种装饰者扩展的方式去加头和尾,而保留中间数据层的原有属性。
代码实现
利用DecorateAdapter去装饰RecyclerView.Adapter,从而扩展HeadView、FooterView
中间内容我们使用contentAdapter来表示,假设就是简单的Item结构,就不做代码介绍了。
第一步:创建装饰器DecorateAdapter
创建装饰器DecorateAdapter并实现增加头部和尾部Item的相关方法、和成员变量
并将contentAdapter作为原始的内容列表
class DecorateAdapter(val contentAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IdecorateList {/**save head View*/private val headerList: MutableList<View> by lazy {mutableListOf()}/**save footer view*/private val footerList: MutableList<View> by lazy {mutableListOf()}/**常规方法*/............override fun getItemCount(): Int {//记得加上contentAdapter的Item条目return contentAdapter.itemCount + headerList.size + footerList.size}override fun addHeaderView(header: View) {if (!headerList.contains(header)) {headerList.add(header)refreshList()}}override fun removeHeaderView(header: View) {if (headerList.contains(header)) {headerList.remove(header)refreshList()}}override fun addFooterView(foot: View) {if (!footerList.contains(foot)) {footerList.add(foot)refreshList()}}override fun removeFooterView(foot: View) {if (footerList.contains(foot)) {footerList.remove(foot)refreshList()}}override fun refreshList() {notifyDataSetChanged()}
}
第二步:处理头部、中间内容、尾部的绑定关系
- 处理头部、中间、尾部的不同绑定的视图:也就是createHeaderViewHolder处理
/**创建头部的ViewHolder*/
private fun createHeaderViewHolder(view: View): RecyclerView.ViewHolder {return HeaderViewHolder(view)
}/**创建尾部的ViewHolder*/
private fun createFooterViewHolder(view: View): RecyclerView.ViewHolder {return FooterViewHolder(view)
}override fun onCreateViewHolder(parent: ViewGroup, position: Int): RecyclerView.ViewHolder {/**头部样式展示*/if (headerList.isNotEmpty() && position in 0 until headerList.size) {return createHeaderViewHolder(headerList[position])}/**中间内容展示*/val startPosition = if (headerList.isNotEmpty()) headerList.size else 0val endPosition =if (headerList.isNotEmpty()) headerList.size + contentAdapter.itemCount else contentAdapter.itemCountif (position in startPosition until endPosition) {return contentAdapter.onCreateViewHolder(parent, position)}/**尾部样式展示*/return createFooterViewHolder(footerList[position - endPosition]) /**注意这里的取值*/
}
- 处理处理头部、中间、尾部的数据绑定:也就是onBindViewHolder的处理
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {if (headerList.isNotEmpty() && position in 0 until headerList.size) {return}/**中间的内容数据绑定*/val startPosition = if (headerList.isNotEmpty()) headerList.size else 0val endPosition =if (headerList.isNotEmpty()) headerList.size + contentAdapter!!.itemCount else contentAdapter!!.itemCountif (position in startPosition until endPosition) {/**注意计算的时候,要减去HeadView*/contentAdapter?.onBindViewHolder(holder, position - headerList.size)}
}
第三步:装饰器的使用
把内容区域的ContentAdapter,通过DecorateAdapter进行包装,之后调用包装后的decorateAdapter进行添加HeadView
decorate = findViewById(R.id.rv_decorate)
val decorateAdapter = DecorateAdapter(ContentAdapter())
decorate.adapter = decorateAdapter
decorate.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)decorateAdapter.addHeaderView(LayoutInflater.from(this).inflate(R.layout.layout_header, decorate, false)
)
第四步:改进、直接封装一个View出来
把装饰者封在内部
毕竟我们在调用的时候,还是想当一个View直接拿来用,改进一下
class decorateRecyclerView : RecyclerView {private var DecorateAdapter: DecorateAdapter? = null@JvmOverloadsconstructor(context: Context, attributes: AttributeSet? = null) : super(context, attributes)override fun setAdapter(adapter: Adapter<ViewHolder>?) {DecorateAdapter = DecorateAdapter(adapter!!)super.setAdapter(DecorateAdapter)}fun addHeaderView(header: View) {DecorateAdapter?.addHeaderView(header)}fun removeHeaderView(header: View) {DecorateAdapter?.removeHeaderView(header)}fun addFooterView(foot: View) {DecorateAdapter?.addFooterView(foot)}fun removeFooterView(foot: View) {DecorateAdapter?.removeFooterView(foot)}
}
调用 & 使用
decorate = findViewById(R.id.rv_decorate)
decorate.adapter = ContentAdapter()
decorate.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)decorate.addHeaderView(LayoutInflater.from(this).inflate(R.layout.layout_header, decorate, false)
)
decorate.addFooterView(LayoutInflater.from(this).inflate(R.layout.layout_footer, decorate, false)
)
总结
本篇呢,只是想说一下如何去潜移默化的使用设计模式去改变我们的代码。
举了一个扩展RecyclerView头和尾的例子。
如果不用设计模式的话,我想你的头和尾的处理逻辑都是需要冗余在ContentAdapter中的
问题:
1、那么你的ContentAdapter的定义界限是什么?整个页面的业务?那难免太难维护了
2、如果只需要服用ContentAdapter怎么处理?粘贴复制,多造一个类出来?
而通过上面我们介绍的装饰者模式就能解决这两个:复用、耦合的问题