概述

描述

  • 动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。是一种对象结构型模式。

套路

  • 抽象构件(Component)

    具体构件和抽象装饰类的基类,声明了在具体构建中实现的业务方法。
  • 具体构件(ConcreteComponent)

    抽象构件的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
  • 抽象装饰类(Decorator)

    它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。
  • 具体装饰类(ConcreteDecorator)

    抽象装饰类的子类,负责向构件添加新的职责。

使用场景

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类).
  • 示例
    • 一些api的参数请求追加签名验证
    • 数据的增删修改,会包含登录验证的功能、然后再进行对应的操作;
    • 原来单一的日志记录,追加上传、归档等功能
    • 已经设计好的游戏物品,因为临时需求想要扩展额外的功能

优缺点

  • 优点

    • 对于扩展一个对象的功能,装饰模式比继承更加灵活
    • 可以对一个对象进行多次装饰,从而创造出很多不同行为的组合
    • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
  • 缺点
    • 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
    • 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

UE4 实践

  • 以前进行账户登录都是直接账户密码就可以,后来为了更安全,更好的采集用户的数据,于是都喜欢加上人脸识别了。这时,可以把人脸识别这一步用装饰器来实现

  • 创建构件抽象类、具体类

    UCLASS(Abstract) // 抽象构件类 —— 账户登录
    class DESIGNPATTERNS_API ULogin : public UObject
    {
    GENERATED_BODY() protected: public:
    virtual bool LoginVerify(const FString& pName, const FString& pPassword) {
    return true;
    }
    }; UCLASS() // 具体构件类 —— 账户登录 联网版本
    class DESIGNPATTERNS_API UWebLogin : public ULogin
    {
    GENERATED_BODY() protected: public:
    virtual bool LoginVerify(const FString& pName, const FString& pPassword) override {
    bool result;
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" LinkWeb:Account ID Verify"));
    result = true;
    return result;
    }
    };
  • 创建装饰具体类(省略抽象类)

    UCLASS() // 装饰器具体类 —— 扩展人脸识别步骤
    class DESIGNPATTERNS_API UWebLoginWithFaceID : public ULogin
    {
    GENERATED_BODY() protected:
    // 被装饰的对象
    UPROPERTY();
    ULogin* m_pLoginObj;
    public:
    // 初始化被装饰的对象
    void Init(ULogin* pLoginObj) {
    m_pLoginObj = pLoginObj;
    } // 装饰的新功能 —— 人脸识别
    bool FaceIDVerify(const FString& pName) {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" %s Face ID Verify"), *pName);
    return true;
    } virtual bool LoginVerify(const FString& pName, const FString& pPassword) override {
    bool result;
    result = m_pLoginObj->LoginVerify(pName, pPassword);
    // 追加人脸识别步骤
    result = result && FaceIDVerify(pName);
    return result;
    }
    };
  • 调用测试

    UCLASS()
    class DESIGNPATTERNS_API ADecoratorTestActor : public AActor
    {
    GENERATED_BODY() public:
    ADecoratorTestActor();
    virtual void Tick(float DeltaTime) override; protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override {
    // 被装饰对象及登录步骤
    ULogin* WebLogin = NewObject<UWebLogin>();
    WebLogin->LoginVerify("admin", "123456"); // 装饰器对象及初始化
    UWebLoginWithFaceID* WebLoginWithFaceID = NewObject<UWebLoginWithFaceID>();
    WebLoginWithFaceID->Init(WebLogin); // 装饰后的登录步骤
    WebLoginWithFaceID->LoginVerify("admin", "123456");
    }
    };
  • 调式输出

    # 旧登录方式
    LogTemp: Warning: UWebLogin::LoginVerify LinkWeb:Account ID Verify # 新登录方式
    LogTemp: Warning: UWebLogin::LoginVerify LinkWeb:Account ID Verify
    LogTemp: Warning: UWebLoginWithFaceID::FaceIDVerify admin Face ID Verify

参考

【UE4 设计模式】装饰器模式 Decorator Pattern的更多相关文章

  1. 浅谈设计模式--装饰者模式(Decorator Pattern)

    挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...

  2. 设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 用法

    装饰者模式(Decorator Pattern) Java的IO类 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716 ...

  3. 设计模式 - 装饰者模式(Decorator Pattern) 具体解释

    装饰者模式(Decorator Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者 ...

  4. 23种设计模式之装饰器模式(Decorator Pattern)

    装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包 ...

  5. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  6. c#设计模式之装饰器模式(Decorator Pattern)

    引子 在面向对象语言中,我们常常会听到这样一句话:组合优于继承.那么该如何去理解这句话呢? 下面我将以游戏装备为模型用简单的代码去展示它 先创建一个装备的抽象类,然后创建刀枪2个具体的业务子类 pub ...

  7. 设计模式(三)——装饰器模式(Decorator Pattern)

    发现太过于刻意按照计划来写博客,有点不实际,刚好最近在一个网课上复习AOP的知识,讲到了装饰器模式和代理模式,顺便复习总结一下. 首先了解一下装饰器模式,从名字里面可以看出来,装饰器模式就类似于房子装 ...

  8. 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现

    返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...

  9. 说说设计模式~装饰器模式(Decorator)

    返回目录 装饰器模式,也叫又叫装饰者模式,顾名思义,将一个对象进行包裹,包装,让它变成一个比较满意的对象,这种模式在我们平时项目开发中,经常会用到,事实上,它是处理问题的一种技巧,也很好的扩展了程序, ...

  10. 用最简单的例子理解装饰器模式(Decorator Pattern)

    假设有一个公司要做产品套餐,即把不同的产品组合在一起,不同的组合对应不同的价格.最终呈现出来的效果是:把产品组合的所有元素呈现出来,并显示该组合的价格. 每个产品都有名称和价格,首先设计一个关于产品的 ...

随机推荐

  1. hibernate01

    什么是hibernate ORM框架/持久层框架 jdbc的一个框架 object reference mapping 通过管理对象来改变数据库中的数据 通过管理对象来操作数据库 hibernate的 ...

  2. Spring整合MyBatis小结

    MyBatis在Spring中的配置 我们在Spring中写项目需要运用到数据库时,现在一般用的是MyBatis的框架来帮助我们书写代码,但是学习了SSM就要知道M指的就是MyBatis,在此,在Sp ...

  3. openswan协商流程之(二):main_inI1_outR1()

    主模式第二包:main_inI1_outR1() 文章目录 主模式第二包:main_inI1_outR1() 1. 序言 2. `main_inI1_outR1()`处理流程图 3. `main_in ...

  4. HTTP快速入门

    一.tomcat端口号设置为80,访问时候可以不加:http协议1.1版本可以复用连接,请求结束后会稍微等会: 二. 表单,get方式提交: 三.user-agent告诉服务器是哪个浏览器,代码中解决 ...

  5. vue-element-admin 全局loading加载等待

    最近遇到需求: 全局加载loading,所有接口都要可以手动控制是否展示加载等待的功能 当拿到这个需求的时候我是拒绝的,因为我以及局部写好了0.0,这是要大改呀....,没办法老板的要求,只能硬着头皮 ...

  6. golang isPowerOfTwo判断是否是2的幂

    iota.go   strconv包 func isPowerOfTwo(x int) bool { return x & (x -1) } 了解n&(n-1)的作用如下: n& ...

  7. 【Nginx】Linux常用命令------启动、停止、重启

    启动 启动代码格式:nginx安装目录地址 -c nginx配置文件地址 例如: [root@LinuxServer sbin]# /usr/local/nginx/sbin/nginx -c /us ...

  8. RocketMQ详解(三)启动运行原理

    专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...

  9. 【Azure 应用服务】App Service For Linux 部署PHP Laravel 项目,如何修改首页路径为 wwwroot\public\index.php

    问题描述 参考官方文档部署 PHP Laravel 项目到App Service for Linux环境中,但是访问应用时候遇见了500 Server Error 错误. 从部署的日志中,可以明确看出 ...

  10. js 模板方法模式

    * 分离出共同点 function Beverage() {} Beverage.prototype.boilWater = function() { console.log("把水煮沸&q ...