Android设计模式详解之装饰模式

news2024/9/29 11:35:03

前言

装饰模式也称为包装模式,结构型设计模式之一;

定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式生成子类更为灵活;

使用场景:需要透明且动态地扩展类的功能时;

UML类图:
装饰模式UML类图
Component:抽象组件,可以是一个接口或抽象类,充当的就是被装饰的原始对象;
ConcreteComponent:组件具体实现类;该类是Component类的基本实现,也是我们装饰的具体对象;
Decorator:抽象装饰者,为了装饰我们的组件对象,内部持有一个指向组件对象的引用,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类;
ConcreteDecoratorA、ConcreteDecoratorB:装饰者具体实现类,对抽象装饰者的具体实现;

模板代码

  • 定义抽象组件,Component
/**
 * 抽象组件
 */
abstract class Component {

    abstract fun operate()
}
  • 定义具体被装饰类,ConcreteComponent
/**
 * 具体被装饰类
 */
class ConcreteComponent : Component() {
    override fun operate() {

    }
}
  • 定义抽象装饰类,Decorator
/**
 * 抽象装饰类
 */
abstract class Decorator(private val component: Component) : Component() {

    override fun operate() {
        component.operate()
    }

}
  • 定义具体装饰类,ConcreteDecorator
/**
 * 具体装饰类
 */
class ConcreteDecorator(component: Component) : Decorator(component) {

    override fun operate() {
        operateA()
        super.operate()
        //方法装饰,增强
        operateB()
    }

    /**
     * 自定义装饰方法A
     */
    private fun operateA() {

    }


    /**
     * 自定义装饰方法B
     */
    private fun operateB() {

    }
}
  • 代码调用示例
//构造被装饰的对象
val component = ConcreteComponent()
//具体装饰类
val concreteDecorator = ConcreteDecorator(component)
concreteDecorator.operate()

示例代码

这里我们以员工进行举例,以员工为抽象组件,抽象行为为工作,具体被装饰的对象假如为互联网员工,然后根据职位不同进行装饰,如普通程序员可以一边工作一边摸鱼,而部门主管不仅一边工作一边摸鱼,还一边监视其他员工;下面我们使用装饰模式来实现:

  • 定义抽象组件,员工类Staff
abstract class Staff {
    abstract fun work()
}
  • 定义具体被装饰类,公司员工ConcreteStaff
/**
 * 具体被装饰类,公司员工
 */
class ConcreteStaff : Staff() {
    override fun work() {
        println("努力上班中...")
    }
}
  • 定义抽象装饰类,程序员装饰类EngineerDecorator
/**
 * 抽象装饰类,程序员装饰类
 */
abstract class EngineerDecorator(private val staff: Staff) : Staff() {

    override fun work() {
        staff.work()
    }

}
  • 定义具体装饰类,普通程序员CommonEngineerStaff
/**
 * 普通程序员
 */
class CommonEngineerStaff(staff: Staff) : EngineerDecorator(staff) {

    override fun work() {
        super.work()
        rest()
    }

    private fun rest() {
        println("休息一会,偷偷摸摸鱼...")
    }
}
  • 定义具体装饰类,部门主管GroupEngineerStaff

/**
 * 部门主管
 */
class GroupEngineerStaff(staff: Staff) : EngineerDecorator(staff) {

    override fun work() {
        super.work()
        rest()
        checkOthers()
    }

    private fun rest() {
        println("休息一会,喝个咖啡~~")
    }

    private fun checkOthers() {
        println("看一下,哪个龟儿子在偷懒...")
    }
}
  • 编写测试代码验证
object Test {

    @JvmStatic
    fun main(args: Array<String>) {
        //构造被装饰的对象
        val staff = ConcreteStaff()
        //普通代码狗
        val commonEngineerStaff = CommonEngineerStaff(staff)
        commonEngineerStaff.work()
        println("------------------------------")
        println("------------------------------")
        //部门主管
        val groupEngineerStaff = GroupEngineerStaff(staff)
        groupEngineerStaff.work()
    }
}

结果输出:

努力上班中...
休息一会,偷偷摸摸鱼...
------------------------------
------------------------------
努力上班中...
休息一会,喝个咖啡~~
看一下,哪个龟儿子在偷懒...

Android源码中的装修模式

  • Context、ContextImpl、ContextWrapper,我们简单分析下源码:
    首先看下Context
public abstract class Context {
    public abstract void startActivity(@RequiresPermission Intent intent);
      public abstract void sendBroadcast(@RequiresPermission Intent intent);
     public abstract ComponentName startService(Intent service);
     ...
}

可以看到Context是一个抽象类,定义了很多关键的抽象方法,如启动Activity、发送广播、开启服务等,
我们知道它的具体实现类为ContextImpl

class ContextImpl extends Context {
 @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        ...
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }
}

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }


    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
                    false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

可以看到它实现了Context中的所有抽象方法,我们在看下ContextWrapper这个类;

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    public Context getBaseContext() {
        return mBase;
    }


 @Override
    public void startActivity(Intent intent) {
        mBase.startActivity(intent);
    }

    /** @hide */
    @Override
    public void startActivityAsUser(Intent intent, UserHandle user) {
        mBase.startActivityAsUser(intent, user);
    }

  @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }

    @Override
    public void sendBroadcast(Intent intent, String receiverPermission) {
        mBase.sendBroadcast(intent, receiverPermission);
    }
}

可以看到,ContextWrapper持有Context对象,并重写了一系列的抽象方法,很明显,这是典型的装饰模式的运用,ContextWrapper充当具体的装饰者角色,对ContextImpl进行功能增强;

总结

装饰模式在Android中运用的十分广泛,但容易和代理模式混淆,代理模式中代理类也是持有被代理类的对象,但两者又有很大的区别:装饰模式是对所要装饰的对象的功能增强,而代理模式只是对代理的对象进行调用,不会对对象本身的功能有所增强;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/128931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零经验出海报单,看跨境电商小白如何在Starday突出重围

随着大数据、云计算等一系列新颖先进的技术概念引入&#xff0c;全球经济市场呈现出以往难以想象的活跃&#xff0c;世界各地的贸易订单都可以借助互联网渠道在数秒内完成全流程。“跨境电商”这一概念正是全球互联网技术普及应用下的附属品&#xff0c;更是经济全球化时代发展…

第五章. 可视化数据分析图表—Seaborn图表(线性回归模型,箱型图,核密度图,提琴图)

第五章. 可视化数据分析图 5.7 Seaborn图表 Seaborn是一个基于Matplotlib的高级可视化效果库&#xff0c;偏向于统计图表&#xff0c;主要针对的是数据挖掘和机器学习中的变量特征选取&#xff0c;相比Matplotlib&#xff0c;他的语法相对简单&#xff0c;但是具有一定的局限性…

《Java高并发与集合框架》第三部分在高并发场景中工作的集合

《Java高并发与集合框架》第三部分在高并发场景中工作的集合前言1.高并发场景中的List、Map和Set集合1.1 CopyOnWriteArrayList1.2 CopyOnWriteArrayList不支持的使用场景1.3 CopyOnWriteArrayList主要方法1.4 java.util.Collections.synchronizedList()方法的补充作用1.4.1 Co…

Allegro如何实现交换pin操作详细指导

Allegro如何实现交换pin操作详细指导 在做PCB设计的时候,换pin是用的较多的功能,换pin可以让线序更加的顺,方便布线。但是前提是确保网络的交换是被允许的 下面用下图为例介绍Allegro中是如何实现交换pin的 具体操作如下 选择File选择Export-Libraries

2022年终,盘点IT行业全年10大事件

白云苍狗&#xff0c;一眨眼&#xff0c;2022年就来到了尾声。这一年里&#xff0c;IT行业发生了不少的大事。有喜有忧&#xff0c;令人目不暇接&#xff0c;显现出IT行业风云变幻的一面。 本期&#xff0c;知了姐为大家整理了近一年来&#xff0c;IT行业发生的10件大事。 NO…

Linux下安装mysql

下载地址&#xff1a; https://dev.mysql.com/downloads/mysql/ 1.解压mysql 文件包&#xff0c;解压路径/home/mysql tar -zxvf mysql-8.0.31-linux-glibc2.12-x86_64.tar 2.编写配置 [client] #password your_password port 3306 socket /home/mysql/…

无线网络监控分析工具

多年来&#xff0c;网络设备已经从房间大小的机器急剧转变为小型便携式设备。随着设备尺寸发生巨大变化&#xff0c;将这些设备相互连接所涉及的技术也发生了巨大变化。这些剧烈变化的结果是无线网络的形成。无线网络的优势在于网络中的各种设备之间不需要物理连接。此外&#…

GoLang ~ 远程调试

前提条件 在编译go项目时&#xff0c;使用​​go build -gcflags "all-N -l"​​&#xff0c;关闭内联优化&#xff0c;以支持debug。 关于​​-gcflags "-N -l"​​参数的解释&#xff1a; 编译时&#xff0c;如果编译的结果需要gdb调试则使用参数​​-…

ASEMI整流桥2W10,DB107S和KBP307封装参数对比

编辑-Z ASEMI整流桥2W10&#xff0c;DB107S和KBP307是很常见的型号&#xff0c;今天就把整流桥2W10&#xff0c;DB107S和KBP307的封装参数对比一小&#xff0c;以便大家在选型时有更好的参考。 2W10参数&#xff1a; 型号&#xff1a;2W10 封装&#xff1a;WOB-4 最大重复峰…

Redis实现全局唯一id,实现优惠卷秒杀的下单功能

Redis实现全局唯一id public class RedisIdWorker {private StringRedisTemplate stringRedisTemplate;public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate stringRedisTemplate;}//开始时间戳private static final long BEGIN_TIMEST…

Postman之接口关联

一、前言 在我们做接口测试时&#xff0c;绝大多数测试人员都会使用 Postman 来进行测试&#xff0c;因为 Postman 的易用性非常好。进行单接口测的时候十分方便&#xff0c;但是实际项目上很多接口都会有依赖关系&#xff0c;这使得每次接口请求前&#xff0c;都要先手动获取…

JMeter操作笔记

通过这个图&#xff0c;我们可以看到一个简单的计算逻辑&#xff1a; 1. 如果有 10000 个在线用户数&#xff0c;同时并发度是 1%&#xff0c;那显然并发用户数就是 100。 2. 如果每个线程的 20TPS&#xff0c;显然只需要 5 个线程就够了&#xff08;请注意&#xff0c;这里…

函数编程和Stream

在函数编程里用到了一些Lamada语法&#xff0c;因此要先了解一些lamada的内容&#xff0c;然后再了解函数编程&#xff0c;进一步再去了解stream 一、lamada使用语法 1.1、使用格式 lambda 表达式的语法格式如下&#xff1a; (parameters) -> expression 或 (parameters…

专家通过六点考证唐村《李氏族谱》:辨别家谱真伪,有这些窍门

如何辨别家谱真实性 家谱与史书、地方志都是史学界无比重视的史料文献&#xff0c;诸如唐村《李氏族谱》就为我们解开了明末、传统武术、太极拳等谜团&#xff0c;也让我们站在社会底层的角度看到了明末清初的种种变革和生活影响。但家谱的内容相比较史书与地方志而言&#xf…

DEJA_VU3D - Cesium功能集 之 091-绘制等高线(纯前端)

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小130个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(尽可能把代码简洁一些)。博文内容…

Allegro如何实现交换functions操作详细指导

Allegro如何实现交换functions操作详细指导 在做PCB设计的时候,换function也是用的较多的功能。但是前提是确保交换是被允许的 同样下面用下图为例介绍Allegro中是如何实现交换function的 具体操作如下 选择File选择Export-Libraries

学习使用html2canvas生成渐变色背景图片

学习使用html2canvas生成渐变色背景图片全部代码html2canvas官网生成图片的下载全部代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>生成渐变色背景图片</title> </head><style>#grad1 {width: 75…

c#入门-数字的字面量

指定类型 整数类型适应性类型 通常情况下&#xff0c;整数的字面量写出来是int类型。 如果数字足够大&#xff0c;那么会逐渐变成long&#xff0c;ulong类型 指定整数类型 或者&#xff0c;在数字后加上L&#xff08;不区分大小写&#xff0c;但一般用大写的L&#xff0c;…

Blender K帧与曲线编辑器

文章目录关键帧.三种K帧方式.自动K帧.物体属性K帧.快捷键K帧.曲线编辑器.打开曲线编辑器.曲线编辑器介绍.控制柄类型.插值模式.关键帧. 1 点击一个模型&#xff0c;即可在时间轴上看到这个模型的关键帧 2 blender的关键帧使用菱形表示 3 未选中的关键帧是灰色&#xff0c;选中…

Eyeshot 2023 预期 Eyeshot 2023 二月发布

Eyeshot 2023 预期 定价和包装 Eyeshot 2023 许可证将仅限于多平台。为了简化激活码的管理并防止平台升级/降级/切换疯狂&#xff0c;所有 Eyeshot 2023 许可证将包括 WinForms、WPF 和中立的跨平台核心。 因此&#xff0c;客户可以免费试用 WinForms、WPF 或中立的跨平台核心&…