• 结构型设计模式之装饰模式:DecoratorPattern


    前言

    装饰模式(Decorator Pattern) 也称为包装模式,结构型设计模式之一。 其使用一种对客户端透明的方式来动态地扩展对象功能,同时它也是继承关系的一种替代方案。

    定义

    装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

    扩展

    扩展是一种十分强大的机制,可以让你在不用继承的情况下,给已存在的类、结构体或者枚举类添加一些新的功能。最重要的一点是,你可以在你没有访问权限的情况下扩展已有类。这意味着你甚至可以扩展 Cocoa 的类,比如 UIView 或者 UIImage 。

    举个例子,在编译时新加的方法可以像扩展类的正常方法一样执行。这和装饰器模式有点不同,因为扩展不会持有扩展类的对象。

    使用场景

    1. 需要扩展一个类的功能,或给一个类添加附加职责。

    2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

    3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使用继承关系实现不现实。

    4. 当不能采用生成子类的方法进行扩充时。比如类定义被隐藏或类定义无法被继承。

    UML

    • Component:抽象组件,给出一个抽象接口,以规范准备接收附加能力的对象。

    • ConcreteComponent: 具体组件,定义一个将要接收附加能力的类,即被装饰的具体对象。

    • Decorator: 抽象装饰者,其职责就是装饰我们的组件,其内部会有一个指向组件对象的引用

    • ConcreteDecoratorA, ConcreteDecoratorB: 装饰者的具体实现类,用于附加上不同的能力

    如何使用扩展

    swift

    extension Double{
     var km : Double { return self * 1000.0 }
     var m: Double { return self }
     var cm: Double { return self / 100.0 }
     var mm: Double { return self / 1000.0 }
     var ft: Double { return self / 3.28084 }
    }
    let oneInch = 25.4.mm;
    print("One inch is \(oneInch)meters")
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    objective-c

    例子1

    //MyClass.h
    @interface MyClass : NSObject  
    - (float)value;  
    @end  
    
    //MyClass.m
    @interface MyClass () { //注意此处:扩展  
     float value;
    }  
    - (void)setValue:(float)newValue;  
    @end  
    
    @implementation MyClass  
    
    - (float)value {  
     return value;
    }  
    
    - (void)setValue:(float)newValue {  
     value = newValue;
    }  
    
    @end  
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    例子2

    //Person_extension.h
    #import "Person.h"
    
    @interface Person () {
     NSString *_someStr;
    }
    
    @property NSObject *extraProperty;
    @property (readwrite) NSString *uniqueIdentifier;
    
    @end
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    委托

    装饰者模式的另一种实现方案是委托。在这种机制下,一个对象可以和另一个对象相关联。比如你在用UITableView,你必须实现tableView(_:numberOfRowsInSection:)这个委托方法。 你不应该指望UITableView知道你有多少数据,这是个应用层该解决的问题。所以,数据相关的计算应该通过UITableView的委托来解决。这样可以让UITableView和数据层分别独立。视图层就负责显示数据,你递过来什么我就显示什么。

    下面这张图很好的解释了UITableView的工作过程:

    UITableView的工作仅仅是展示数据,但是最终它需要知道自己要展示那些数据,这时就可以向它的委托询问。在 objc 的委托模式里,一个类可以通过协议来声明可选或者必须的方法。

    看起来似乎继承然后重写必须的方法来的更简单一点。但是考虑一下这个问题:继承的结果必定是一个独立的类,如果你想让某个对象成为多个对象的委托,那么子类这招就行不通了。

    注意:委托模式十分重要,苹果在 UIKit 中大量使用了该模式,基本上随处可见。

    如何使用委托模式

    swift

    例子1

    protocol FullyNamed {
     var fullName: String { get }
    }
    struct Person: FullyNamed {
     var fullName: String
    }
    let john = Person(fullName: "John Appleseed")
    // john.fullName 为 "John Appleseed"
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    例子2

    //定义一个协议
    protocol LogManagerDelegate {
     func writeLog()
    }
    
    //用户登录类
    class UserController {
     var delegate : LogManagerDelegate?
    
     func login() {
     //查看是否有委托,然后调用它
     delegate?.writeLog()
     }
    }
    
    //日志管理类
    class SqliteLogManager : LogManagerDelegate {
     func writeLog() {
     print("将日志记录到sqlite数据库中")
     }
    }
    
    
    //使用
    let userController = UserController()
    userController.login()  //不做任何事
    
    let sqliteLogManager = SqliteLogManager()
    userController.delegate = sqliteLogManager
    userController.login()  //输出“将日志记录到sqlite数据库中”
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Objective - C

    //Mydelegate.h
    //可以单独放在一个.h文件,也可以直接放入A.h中
    @protocol Mydelegate//协议的声明 中
    -(void)Fun;
    @end
    
    //A.h
    #import "Mydelegate.h"
    @interface A:NSObject
    {
     id delegate;//声明一个委托对象,我们要把事情委托给实现Mydelegate协议的类
    }
    @property(assign,nonatomic) id delegate;
    @end
    
    //A.m
    #import "A.h"
    @implementation
    -(void)FunToOther
    {
     [delegate Fun];//将消息发送给委托去处理
    }
    @end
    
    //B.h
    #import"A.h"
    @interface B:NSObject
    @property(strong,nonatomic) A *a;
    @end
    
    //B.m
    #import "B.h"
    @implementation
    -(void)init
    {
     _a = [[A alloc] init];
     _a.delegate = self;
    }
    #prage mark - MyDelegate
    -(void)fun
    {
     //实现Mydelegate中制定的方法
    }
    @end
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    有需要文中完整代码的同学: 现在私信发送 “底层源码” 即可免费获取

    现在私信还可以获取《更多 Android 源码解析+学习大纲+面试真题》

    总结

    优点

    装饰者模式的性能非常好, 在项目中,你会有非常多的因素考虑不到,特别是业务的变更,不时地冒出一个需求,装饰模式可以给我们很好的帮助,通过装饰模式重新封装一 个类,而不是通过继承来完成, 对原有程序没有变更。

    缺点

    可忽略,还是那句话,类增加了,麻烦。可以在实际需要时再抽象组件,避免过度设计

    最后我想说:

    对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

    技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

    Android 架构师之路还很漫长,与君共勉

  • 相关阅读:
    [RootersCTF2019]I_<3_Flask-1|SSTI注入
    NFT与奢侈品文化的天然契合:NFT满足了人类寻求独特性和地位的天性
    数字验证学习笔记——SystemVerilog芯片验证10 ——类的成员
    leetcode 1423. Maximum Points You Can Obtain from Cards(从牌中能得到的最大点数和)
    【并发编程】线程间的通信
    Asp.Net Core6.0中MediatR的应用CQRS
    电子期刊制作神器,轻松打造专业级刊物
    【YOLO系列】YOLOv2
    2023年工单管理系统排行榜单
    现代 React Web 开发实战——kanban实现卡片拖拽
  • 原文地址:https://blog.csdn.net/m0_70748845/article/details/125995543