当前位置: 首页 > news >正文

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

前言


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

总结


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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Linux】FRP:内网穿透
  • 使用 AI进行绘画初体验
  • 易语言教程——第四章—第一个程序—串口调试助手
  • 跨vue、react、angular框架渲染
  • 使用Vue创建cesium项目模版该如何选择?
  • 用Python在PDF文档中创建动作
  • 使用实例:xxl-job应用在spring cloud微服务下
  • uniapp组件用法
  • PTA - C语言接口题集1
  • linux下cpu多核运行程序以及运行时间统计
  • 复杂工件的高效测量方案:自动化三坐标测量与影像测量技术集成
  • 分类预测|基于黑翅鸢优化BKA-Transformer-LSTM组合模型的数据预测Matlab程序多特征输入多类别输出
  • 大语言模型算力优化策略:基于并行化技术的算力共享平台研究
  • 是否应该使用WordPress自动更新的功能
  • 虚幻5|技能栏优化(1)---优化技能UI,并添加多个技能
  • [nginx文档翻译系列] 控制nginx
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • css的样式优先级
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • java 多线程基础, 我觉得还是有必要看看的
  • Javascript Math对象和Date对象常用方法详解
  • uni-app项目数字滚动
  • vue-cli在webpack的配置文件探究
  • 阿里云购买磁盘后挂载
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 关于Flux,Vuex,Redux的思考
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 基于游标的分页接口实现
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 手机端车牌号码键盘的vue组件
  • 阿里云API、SDK和CLI应用实践方案
  • ​比特币大跌的 2 个原因
  • ​第20课 在Android Native开发中加入新的C++类
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • ‌JavaScript 数据类型转换
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (层次遍历)104. 二叉树的最大深度
  • (二)linux使用docker容器运行mysql
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • .Net 8.0 新的变化
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes
  • .NET 反射 Reflect
  • .Net 执行Linux下多行shell命令方法
  • .NET基础篇——反射的奥妙
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • .php文件都打不开,打不开php文件怎么办
  • @Documented注解的作用
  • @vue/cli 3.x+引入jQuery
  • [\u4e00-\u9fa5] //匹配中文字符
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改