前言
装饰器模式(Decorator Pattern
),用于动态地为对象添加新功能,而无需修改其结构,通过使用不用装饰类及这些装饰类的排列组合,可以实现不同的功能和效果,但是这样的效果就是会增加很多类,过度使用增加程序的复杂性。
适配器模式主要包括以下几个角色:
1、组件接口(Component
) :定义一个对象接口,可以有基本功能或抽象功能。
2、具体组件(ConcreteComponent
) :实现组件接口的基本功能。
3、装饰器(Decorator
) :持有一个组件对象的引用,并实现组件接口。
4、具体装饰器(ConcreteDecorator
):实现了装饰器,并为组件对象添加了具体的附加功能。
实现
以下例子实现装饰器模式,定义图像处理接口BitmapProcessor
,提供处理图片方法方法,具体组件实现基本的 BitmapProcessor
,提供原始的 Bitmap
对象。
kotlin
interface BitmapProcessor {
fun process(bitmap: Bitmap): Bitmap
}
class BasicBitmapProcessor(private val bitmap: Bitmap) : BitmapProcessor {
override fun process(bitmap: Bitmap): Bitmap {
return this.bitmap
}
}
实现一个通用的装饰器,持有一个 BitmapProcessor
对象的引用。
kotlin
abstract class BitmapProcessDecorator(private val process: BitmapProcessor) : BitmapProcessor {
override fun process(bitmap: Bitmap): Bitmap {
return process.process(bitmap)
}
}
实现具体装饰器继承,选择图片、缩放图片功能。
kotlin
class RotateDecorator(process: BitmapProcessor, private val angle:Float): BitmapProcessDecorator(process) {
override fun process(bitmap: Bitmap): Bitmap {
val matrix = Matrix().apply {
postRotate(angle)
}
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
}
class ScaleDecorator(process: BitmapProcessor, private val sx: Float, private val sy: Float) : BitmapProcessDecorator(process) {
override fun process(bitmap: Bitmap): Bitmap {
val matrix = Matrix().apply {
postScale(sx, sy)
}
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
}
客户端创建对应的装饰器
kotlin
//创建原始图片对象
val originalBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground)
//创建具体图片处理对象
val basicProcessor = BasicBitmapProcessor(originalBitmap)
//创建图片旋转装饰器
val rotateDecorator = RotateDecorator(basicProcessor, 45.0f)
rotateDecorator.process(originalBitmap) //旋转90度
//创建图片缩放装饰器
val scaleDecorator = ScaleDecorator(basicProcessor, 2.0f, 2.0f)
scaleDecorator.process(originalBitmap) //缩放2倍
//处理图片,显示
val processorBitmap= basicProcessor.process(originalBitmap)
mBinding.image.setImageBitmap(processorBitmap)
在Android
中,经常使用的控件RecyclerView
中就提供了装饰器模式的应用,ItemDecoration
它允许你在不修改原始 RecyclerView
的情况下为每个项添加装饰比如分割线、边距等。
kotlin
/**
* An ItemDecoration allows the application to add a special drawing and layout offset
* to specific item views from the adapter's data set. This can be useful for drawing dividers
* between items, highlights, visual grouping boundaries and more.
*/
public abstract static class ItemDecoration {
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn before the item views are
*/
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) {
onDraw(c, parent);
}
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn after the item views are drawn
*/
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent,
@NonNull State state) {
onDrawOver(c, parent);
}
/**
* Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
* the number of pixels that the item view should be inset by, similar to padding or margin.
* The default implementation sets the bounds of outRect to 0 and returns.
*
* <p>
* If this ItemDecoration does not affect the positioning of item views, it should set
* all four fields of <code>outRect</code> (left, top, right, bottom) to zero
* before returning.
*
* <p>
* If you need to access Adapter for additional data, you can call
* {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
* View.
*
* @param outRect Rect to receive the output.
* @param view The child view to decorate
* @param parent RecyclerView this ItemDecoration is decorating
* @param state The current state of RecyclerView.
*/
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
@NonNull RecyclerView parent, @NonNull State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
}
下面实现为RecyclerView
的条目添加分割线,继承ItemDecoration
类,实现onDrawOver
方法。
kotlin
class DividerItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
private val divider: Drawable?
init {
val styledAttributes = context.obtainStyledAttributes(intArrayOf(android.R.attr.listDivider))
divider = styledAttributes.getDrawable(0)
styledAttributes.recycle()
}
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val left = parent.paddingLeft
val right = parent.width - parent.paddingRight
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
val params = child.layoutParams as RecyclerView.LayoutParams
val top = child.bottom + params.bottomMargin
val bottom = top + divider!!.intrinsicHeight
divider.setBounds(left, top, right, bottom)
divider.draw(c)
}
}
}
总结
装饰器模式在需要动态扩展对象功能的场景中非常有用,可以提高灵活性和复用性。然而,它也可能增加系统的复杂性,并带来一定的性能开销。在使用装饰器模式时,需要权衡其优缺点,并根据实际需求做出合理的设计决策。