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

总结

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

相关推荐
滴水成冰-3 小时前
Kotlin-Flow学习笔记
笔记·学习·kotlin
我码玄黄4 小时前
JS 的行为设计模式:策略、观察者与命令模式
javascript·设计模式·命令模式
会敲代码的小张5 小时前
设计模式-观察者模式
java·开发语言·后端·观察者模式·设计模式·代理模式
宗浩多捞5 小时前
C++设计模式(更新中)
开发语言·c++·设计模式
秦哈哈5 小时前
【软件设计】常用设计模式--观察者模式
观察者模式·设计模式
蔚一12 小时前
Java设计模式—面向对象设计原则(四) ----->接口隔离原则(ISP) (完整详解,附有代码+案例)
java·后端·设计模式·intellij-idea·接口隔离原则
严文文-Chris14 小时前
【设计模式-外观】
android·java·设计模式
yyqzjw15 小时前
【设计模式】观察者模式
算法·观察者模式·设计模式
Tech_gis15 小时前
C++ 常用设计模式
设计模式
java_heartLake16 小时前
设计模式之抽象工厂模式
设计模式·抽象工厂模式