浅谈链式编程思想

一切都从一个需求开始

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

常规做法

  • 设计一个计算类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

你可能感兴趣的:(浅谈链式编程思想)