欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

浅谈链式编程思想

程序员文章站 2022-07-12 16:29:17
...

一切都从一个需求开始

  • 项目需求: 设计一个计算器, 可以方便地进行加减乘除等计算

常规做法

  • 设计一个计算类CalculateMaker, 通过其属性result记录计算结果, 当我需要计算10-2+6+2-1时, 代码如下:
CalculateMaker *make = [[CalculateMaker alloc] init];
    make.result += 10;
    make.result -= 2;
    make.result += 6;
    make.result += 2;
    make.result -= 1;
NSLog(@"result = %zd", make.result);

非常规做法

  • 看到以上代码时, 很多人可能会很烦中间的计算, 光是5次计算就占用了5行代码, 有没有办法可以一行解决. 这就引出了今天的主题, 即链式编程. 我们直接看使用链式编程是如何进行计算的:
   NSUInteger result = [NSObject makeCalculator:^(CalculateMaker *make) {
                            make.add(10).minus(2).add(6).add(1).minus(5);
                        }];
   NSLog(@"result = %zd", result);
  • 先不管以上代码的实现原理, 单单是从代码结构上来讲, 理论上我们可以仅仅使用一行代码来实现无穷无尽的加减计算(尽管这行代码可能会很长, 但它也是一行). 关键是使用这种写法, 视觉上也更符合计算等式的逻辑.
  • 那么问题来了, 这段代码是如何做到等价于10-2+6+2-1? 如何做到连续使用点语法? 又是如何做到用(10), (2)这种格式来传值, 并最终得出我们想要的结果呢? 我们把疑问归结为以下三个来逐一分析.

疑问大全

1. CalculateMaker类是什么?
2. NSObject的类方法makeCalculator方法做了什么?
3. make.add(10).minus(2)是如何做到等价于10-2的, 并且连续使用点语法的?

[疑问一] CalculateMaker类是什么?

@interface CalculateMaker : NSObject

@property (nonatomic, assign) NSUInteger result;
- (CalculateMaker * (^)(int value))add;
- (CalculateMaker * (^)(int value))minus;

@end
  • 以上是CalculateMaker类的.h文件, 而根据代码我们不难得出结论, CalculateMaker只负责两件事:
    • 一是提供result属性记录计算结果
    • 二是提供add方法, minus方法进行加法计算和减法计算. (add和minus方法的实现稍后解释)

[疑问二] NSObject的类方法makeCalculator方法做了什么?

  • makeCalculator其实是一个NSObject的类拓展方法, 该方法提供一个block参数, 同时返回计算结果, 详细代码如下:
- (NSUInteger)makeCalculator:(void(^)(CalculateMaker *make))block{
    CalculateMaker *make = [[CalculateMaker alloc] init];   //1. 初始化一个CalculateMaker类
    block(make);               //2. 把CalculateMaker通过block传出去, 也等价于block所涉及的计算直接在这里执行
    return make.result;      //3. CalculateMaker执行完相关计算后, 把结果通过函数返回值传递出去
}

[疑问三] make.add(10).minus(2)是如何做到等价于10-2的, 并且连续使用点语法的?

(在这里我们仅以add为例进行解释)

- (CalculateMaker *(^)(int))add{
    return ^CalculateMaker * (int value) {
        self.result += value;
        return self;
    };
}
  • 以上是add方法的实现, 其本质即执行一段block.
  • 当代码执行make.add(10), CalculateMaker调用add方法执行这段block, 此时10作为 ^CalculateMaker * (int value)这个block的value参数传入, 传入后用于进行加法运算, 然后这段block又返回CalculateMaker自己.
  • 总结来讲, 通过执行make.add(10), CalculateMaker既实现了+10的运算并记录到result中, 而且还把自己作为返回值重新传递出来, 此时我们就可以拿到CalculateMaker, 并继续使用点语法调用minus继续进行计算.

后话

  • 眼尖的读者可能会发现, 这不就是Masonry框架的写法吗?!!! 没错, Masonry正是使用了链式编程来实现对NSLayoutConstraint的封装, 同样使用链式编程的还有远近驰名的Reative Cocoa. 对于常年写业务逻辑代码的工程师而言, 链式编程可能极少会用到, 但是了解链式编程其实不仅可以拓宽编程的认知水平, 而且也能进一步加深对block的理解, 最后如果想进一步了解Masonry实现细节以及链式编程的, 可以参阅以下两篇文章做更深层的学习.
    [1]https://www.jianshu.com/p/2d94a0e579d2
    [2]https://www.cnblogs.com/ludashi/archive/2016/07/11/5591572.html