【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)
        }
    }
}

总结

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

相关推荐
&岁月不待人&27 分钟前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
wrx繁星点点1 小时前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
金池尽干3 小时前
设计模式之——观察者模式
观察者模式·设计模式
也无晴也无风雨3 小时前
代码中的设计模式-策略模式
设计模式·bash·策略模式
小白学大数据3 小时前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
捕鲸叉12 小时前
MVC(Model-View-Controller)模式概述
开发语言·c++·设计模式
wrx繁星点点12 小时前
享元模式:高效管理共享对象的设计模式
java·开发语言·spring·设计模式·maven·intellij-idea·享元模式
凉辰12 小时前
设计模式 策略模式 场景Vue (技术提升)
vue.js·设计模式·策略模式
菜菜-plus13 小时前
java设计模式之策略模式
java·设计模式·策略模式
暗黑起源喵13 小时前
设计模式-迭代器
设计模式