【Kotlin设计模式】Kotlin实现装饰器模式

前言

装饰器模式(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)
        }
    }
}

总结

装饰器模式在需要动态扩展对象功能的场景中非常有用,可以提高灵活性和复用性。然而,它也可能增加系统的复杂性,并带来一定的性能开销。在使用装饰器模式时,需要权衡其优缺点,并根据实际需求做出合理的设计决策。

相关推荐
消失的旧时光-19434 小时前
Android回退按钮处理方法总结
android·开发语言·kotlin
李广坤7 小时前
状态模式(State Pattern)
设计模式
李广坤8 小时前
观察者模式(Observer Pattern)
设计模式
李广坤9 小时前
中介者模式(Mediator Pattern)
设计模式
李广坤9 小时前
迭代器模式(Iterator Pattern)
设计模式
VIjolie9 小时前
协程CoroutineContext理解
kotlin
李广坤10 小时前
解释器模式(Interpreter Pattern)
设计模式
阿无,12 小时前
java23种设计模式之前言
设计模式
Asort13 小时前
JavaScript设计模式(八):组合模式(Composite)——构建灵活可扩展的树形对象结构
前端·javascript·设计模式
数据智能老司机13 小时前
数据工程设计模式——数据基础
大数据·设计模式·架构