前言
装饰器模式(Decorator Pattern
),用于动态地为对象添加新功能,而无需修改其结构,通过使用不用装饰类及这些装饰类的排列组合,可以实现不同的功能和效果,但是这样的效果就是会增加很多类,过度使用增加程序的复杂性。
适配器模式主要包括以下几个角色:
1、组件接口(Component
):定义一个对象接口,可以有基本功能或抽象功能。
2、具体组件(ConcreteComponent
):实现组件接口的基本功能。
3、装饰器(Decorator
):持有一个组件对象的引用,并实现组件接口。
4、具体装饰器(ConcreteDecorator
):实现了装饰器,并为组件对象添加了具体的附加功能。
实现
以下例子实现装饰器模式,定义图像处理接口BitmapProcessor
,提供处理图片方法方法,具体组件实现基本的 BitmapProcessor
,提供原始的 Bitmap
对象。
interface BitmapProcessor {fun process(bitmap: Bitmap): Bitmap
}class BasicBitmapProcessor(private val bitmap: Bitmap) : BitmapProcessor {override fun process(bitmap: Bitmap): Bitmap {return this.bitmap}
}
实现一个通用的装饰器,持有一个 BitmapProcessor
对象的引用。
abstract class BitmapProcessDecorator(private val process: BitmapProcessor) : BitmapProcessor {override fun process(bitmap: Bitmap): Bitmap {return process.process(bitmap)}
}
实现具体装饰器继承,选择图片、缩放图片功能。
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)}
}
客户端创建对应的装饰器
//创建原始图片对象
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
的情况下为每个项添加装饰比如分割线、边距等。
/*** 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
方法。
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.paddingLeftval right = parent.width - parent.paddingRightval childCount = parent.childCountfor (i in 0 until childCount - 1) {val child = parent.getChildAt(i)val params = child.layoutParams as RecyclerView.LayoutParamsval top = child.bottom + params.bottomMarginval bottom = top + divider!!.intrinsicHeightdivider.setBounds(left, top, right, bottom)divider.draw(c)}}
}
总结
装饰器模式在需要动态扩展对象功能的场景中非常有用,可以提高灵活性和复用性。然而,它也可能增加系统的复杂性,并带来一定的性能开销。在使用装饰器模式时,需要权衡其优缺点,并根据实际需求做出合理的设计决策。