• RxJava的前世【RxJava系列之设计模式】


    一. 前言

    学习RxJava,少不了介绍它的设计模式。但我看大部分文章,都是先将其用法介绍一通,然后再结合其用法,讲解其设计模式。这样当然有很多好处,但我个人觉得,这种介绍方式,对于没有接触过RxJava的朋友来说,是不太友好的。

    而我,更倾向于,先把对设计模式的认知,拉齐,然后在讲到用法的时候,大家就会自然而然地理解了它怎么用到的设计模式,从而也就更容易理解源码了,一切都是水到渠成。

    所以,在本篇文章中,大部分内容依然不会涉及RxJava,但其实处处都有RxJava的影子。你需要做的就是完全理解本篇文章的内容,没有理解到的地方请留言,我都会一个一个认真看的。

    不啰嗦了,让我们开始正题吧!

    二. 观察者模式

    1. 什么是观察者模式?

    一个比较书面化的定义是:在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

    通俗一点理解,假如说有两种对象,一个是观察者,一个是被观察者,当一个被观察者对象发生变化的时候,可以通知到所有的观察者对象。所有的观察者对象在接收到这个通知的时候,可以做一些自己的处理。

    2. Android中有没有例子?

    在Android中,观察者模式其实很常见,比如点击事件监听,当view被点击的时候,会通知到它的观察者,也就是调用到你实现的onClick方法。再比如说EventBus,比如LiveData,其实都有运用到观察者模式。

    3. 写个代码?

    本着KISS原则(Keep It Simple, Stupid),观察者模式比较简单,所以在这里,就不写代码了。

    但值得一提的是,RxJava中运用到的观察者模式,和这里有一点微小的差别,但根本思想是一样的。至于是什么微小的差别,等讲到RxJava原理的时候,你就理解了。

    三. 装饰器模式

    1. 什么是装饰器模式?

    可以通俗地理解为,在不改变原有对象的基础上,增强原有对象的功能。

    2. Android中有没有例子?

    我们天天接触的Context,就是一个非常典型的装饰器模式的例子。

    Android中的Context对象是一个核心的组件,它经常被装饰器进行功能扩展和定制。例如,Activity、Service、BroadcastReceiver等都是Context的子类,它们在基本的Context功能上添加了更多的生命周期管理、界面交互和事件处理等功能。

    相当于在没有修改Context的基础上,对Context进行了功能的增强

    3. 写个代码?

    因为我们平时关于装饰器模式,写的不是很多,所以我觉得有必要,以一个很简单的例子,向大家再进一步介绍下装饰器模式。

    假设你经营一家咖啡店,你的顾客可以根据自己的口味定制咖啡。首先,我们有一个抽象的咖啡接口

    public interface Coffee {
        String getDescription();
        double getCost();
    }
    
    • 1
    • 2
    • 3
    • 4

    然后,我们还有一个具体的咖啡实现

    public class SimpleCoffee implements Coffee {
        @Override
        public String getDescription() {
            return "Simple Coffee";
        }
    
        @Override
        public double getCost() {
            return 1.0;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    现在,我们不满足于一个简单的咖啡(SimpleCoffee),而是要有一个可以加入牛奶的咖啡。相当于对原有的咖啡功能进行增强,这时,我们就可以借助装饰器模式来实现。

    首先,声明一个装饰器模式的抽象类,也实现Coffee接口。

    public abstract class CoffeeDecorator implements Coffee {
        protected Coffee coffee;
    
        public CoffeeDecorator(Coffee coffee) {
            this.coffee = coffee;
        }
    
        @Override
        public String getDescription() {
            return coffee.getDescription();
        }
    
        @Override
        public double getCost() {
            return coffee.getCost();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    然后,可以创建一个具体的装饰器类

    public class MilkDecorator extends CoffeeDecorator {
        public MilkDecorator(Coffee coffee) {
            super(coffee);
        }
    
        @Override
        public String getDescription() {
            return super.getDescription() + ", Milk";
        }
    
        @Override
        public double getCost() {
            return super.getCost() + 0.5;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这样我们在使用的时候,顾客可以选择加入咖啡,而不会改变原有的咖啡类

    Coffee simpleCoffee = new SimpleCoffee();
    Coffee coffeeWithMilk = new MilkDecorator(simpleCoffee);
    System.out.println(coffeeWithMilk.getDescription());  // 输出:Simple Coffee, Milk
    System.out.println(coffeeWithMilk.getCost());  // 输出:1.5
    
    • 1
    • 2
    • 3
    • 4
    为什么实现了同一个接口?

    这里大家也会发现一个细节,就是装饰器类,和被装饰类,都实现了同一个接口,在这个例子中就是Coffee接口。这样做的好处就是可以统一以Coffee来接收装饰器类和被装饰类,这使得客户端可以根据需求自由组合装饰器对象,以获得所需的功能组合,方便多次嵌套,自己可以作为装饰器类,也可以作为被装饰类,实现更灵活,符合“基于接口而非实现”的规范


    举个例子,假如客户还想加糖,那么就可以新增一个加糖的装饰器类

    public class SugerDecorator extends CoffeeDecorator {
        public SugerDecorator(Coffee coffee) {
            super(coffee);
        }
    
        @Override
        public String getDescription() {
            return super.getDescription() + ", Suger";
        }
    
        @Override
        public double getCost() {
            return super.getCost() + 0.3;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    然后顾客如果既想加糖,又想加牛奶,就可以这样实现:

    Coffee simpleCoffee = new SimpleCoffee();
    Coffee coffeeWithMilk = new MilkDecorator(simpleCoffee);
    Coffee coffeeWithSuger = new SugerDecorator(coffeeWithMilk);
    
    • 1
    • 2
    • 3

    可以看到,MilkDecorator本身既是装饰器类,也是被装饰类,使得原有对象的功能,可以定制化地增强。而能够实现这些的原因,就是装饰器类和被装饰类,实现了同一个接口

    四. 总结

    本篇文章内容就到这里了,其实本篇文章没有提到RxJava的具体知识,但其实处处都有RxJava的影子。在本篇文章中,你只需要牢牢掌握观察者模式和装饰器模式,理解我举的例子,就可以了。等看到RxJava的原理的文章时,你就会豁然开朗!

    Android 学习笔录

    Android 性能优化篇:https://qr18.cn/FVlo89
    Android 车载篇:https://qr18.cn/F05ZCM
    Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
    Android Framework底层原理篇:https://qr18.cn/AQpN4J
    Android 音视频篇:https://qr18.cn/Ei3VPD
    Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
    Kotlin 篇:https://qr18.cn/CdjtAF
    Gradle 篇:https://qr18.cn/DzrmMB
    OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
    Flutter 篇:https://qr18.cn/DIvKma
    Android 八大知识体:https://qr18.cn/CyxarU
    Android 核心笔记:https://qr21.cn/CaZQLo
    Android 往年面试题锦:https://qr18.cn/CKV8OZ
    2023年最新Android 面试题集:https://qr18.cn/CgxrRy
    Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
    音视频面试题锦:https://qr18.cn/AcV6Ap

  • 相关阅读:
    Linux性能优化--性能追踪3:系统级迟缓(prelink)
    全量知识系统 程序详细设计 库模式的存储库模型: “三生”(派生衍生自生) (Q&A SmartChat)
    查看单元测试用例覆盖率新姿势:IDEA 集成 JaCoCo
    redis笔记
    Redis作者谈Redis应用场景
    【Python】面向对象版学生管理系统(文末有源代码)
    你知道用Woof创建的Linux吗?
    Linux下redis单机安装、主从搭建及哨兵模式搭建及springboot整合测试
    PMP考完后应该考什么?
    算法实战:亲自写红黑树之五 删除erase的平衡
  • 原文地址:https://blog.csdn.net/maniuT/article/details/132642842