iOS 中的链式编程函数式编程入门

Posted 昊卓集团

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 中的链式编程函数式编程入门相关的知识,希望对你有一定的参考价值。

iOS 中的链式编程、函数式编程入门


对一个程序猿来说,从一开始接触编程后会逐渐经历好几个不同的编程思想。包括过程式编程、面向对象编程、响应式编程、函数式编程、链式编程等等。

过程式编程的特点是随着程序的编写逐步进行,写到哪儿运行到哪儿。

面向对象的特点是万物皆对象。很著名的例子:把大象放进冰箱。

响应式编程的特点是一方触发,多方响应。OC中的KVO、通知中心就是这种。触发者只负责触发,不理会结果。

函数式编程的特点是将函数作为一等公民,当作参数和返回值使用。典型的如OC和Swift 中的 map函数、fiflt函数、reduce函数等。每个函数的处理结果给到下一个函数,最后的结果由自身函数调出。

链式编程的特点是运用点语法将很多个函数串联起来。典型的例子是OC中的Masnary和Swift 中的Snpkit。

这篇文章主要介绍函数式编程和链式编程的实现

链式编程

链式编程的特点是使用点语法将对象的多个函数连起来调用。就像这样

    obj.func1(par).func2
   (par).func3(par)

以一个例子来实现。假设我需要做一个字符串处理的扩展,其中包涵拼接字符删除最后一个字符修改最后一个字符这三个功能。在OC和Swift 中,这些函数都有现成,但是我想它们能够联合起来调用。假设我已经给这三个函数分别去名字叫:addString,

removeLastString,

alterLastString.

而我想像下面这样调用:

 NSString *str = @
"abcdefg";
NSString *newStr = str.
addString(@"123").
removeLastString().add
(@"555"). alter
LastString
("*")  NSLog(@"%@",
newStr );

最后输出的结果是:abcdefg1255*.这个应该很容易理解了。
接下来我分别使用OC和Swift来实现。

在OC中(链式编程)

新建一个工具类StringManegeTool,这个类包涵了一个初始化的函数:initWithString以及一个启动函数doSomething.并且包含了若干个block做为属性,以便使用点语法。

////  StringManegeTool.h
//  funTest////  Created
by JD on 2017/11/4.//  
Copyright © 2017年 JD.
All rights reserved.//
#import <Foundation/
Foundation.h>@class
StringManegeTool;typedef
StringManegeTool* (^
TESTBlock1)(NSString*);
typedef StringManegeTool*
(^TESTBlock2)(void);
@interface
StringManegeTool:
NSObject- (instancetype)
initWithString:(NSString*)
str; - (NSString*)doSomething:
(void (^)(StringManegeTool
*))maker;@property
(nonatomic,copy)
TESTBlock1
addString;@property
(nonatomic,copy)
TESTBlock2
removeLastString;@property
(nonatomic,copy)
TESTBlock1
alertLastString;@end

.m文件中实现。在初始化方法中实现了block,并且在doSomthing中实现了调用block。

////  StringManegeTool.m
//  funTest////  Created
by JD on 2017/11/4.//  
Copyright © 2017年 JD.
All rights reserved.//
#import "StringManegeTool.
h"#import <Foundation/
Foundation.h>@interface
StringManegeTool ()
@property(nonatomic,
strong) NSMutableString*
buffStr;@end@
implementation
StringManegeTool-
(instancetype)
initWithString
:(NSString*)str{    self =
[super init];    if (self)
{        self.buffStr =
[[NSMutableString alloc]
initWithString:str];        __weak
StringManegeTool *weakSelf
= self;   self.addString
= ^StringManegeTool *
(NSString *str) {            [weakSelf.
buffStr appendString:
str];            return
 weakSelf;        };                self.
 removeLastString =
  ^StringManegeTool *{            [weakSelf.
buffStr
deleteCharactersInRange:
NSMakeRange(weakSelf.
buffStr.length-1, 1)];
      return  weakSelf;        };             self.alertLastString
    = ^StringManegeTool
    *(NSString *str) {            [weakSelf.
buffStr
replaceCharactersInRange
:NSMakeRange(weakSelf.
buffStr.length-1, 1)
withString:str];  
        return weakSelf;        };    }    return self; } - (NSString*)doSomething:
(void (^)
(StringManegeTool
*))maker{        maker(self);  
 return self.buffStr; }@end

接下来我可以这样调用:

 StringManegeTool *tool
 = [[StringManegeTool
 alloc] initWithString:
 @"abcdefg"];   NSString *newStr =
 [tool doSomething:^
 (StringManegeTool
 *make) {        make.addString(
 @"123").removeLastString
().addString(@"555").
alertLastString(@"*");    }];     NSLog(@"%@",newStr); 打印结果//2017-11-04
15:36:08.495 funTest[1661:
121049] abcdefg1255*

回忆一下Masnary。熟悉的味道!

再来看看Swift中如何实现链式编程
////StringManegeTool-
InSwift.swift//  
funTest////  Created
by JD on 2017/11/4.//
  Copyright © 2017年 JD.
   All rights reserved.
   //import UIKitclass
 StringManegeToolInSwift:
 NSObject {    var bufStr:String =
 String()        convenience init(_
  withString:String){  
       self.init();  
self.bufStr = withString    }     func doSomething(_ make:
(StringManegeToolInSwift)
 ->())->String{        make(self)        
 return self.bufStr    }        func addString(_
 string:String)->
 StringManegeToolInSwift
 {  self.bufStr.append
 (string)   return self    }      func remoLastString()->
StringManegeToolInSwift{        let end  = self.
bufStr.endIndex        let start = self.
bufStr.index(before: end)                self.bufStr.
removeSubrange
(start..<end)
return self    }     func alertLastString(_
string:String) ->
StringManegeToolInSwift{  let end  = self.bufStr.
endIndex  let start = self.bufStr.
index(before: end)      
self.bufStr.
replaceSubrange
(start..<end, with:
string)
       return self    }        /// 调用 class func actionDo(){        let tool =
StringManegeToolInSwift.
init("abcdefg")                let newString =
tool.doSomething {
(maker) in    maker.addString("123")
.remoLastString()
.addString
("555").alertLastString
("*")}                print(newString)    }//打印:         abcdefg1255* }

说实话,Swift写起来要简单太多了。

总结一下:ios中,链式编程的特点是调用返回值为自身的函数或者Block。再结合map等函数的映射转换,这样可以使得代码变的非常灵活。

函数式编程

我之前一直把函数式编程理解为高阶函数,其实这就是高阶函数。先看一个很典型的例子,照样,我们从CO开始。

    NSArray<NSString*>
*arr = @[@"252",@"55541",
@"2295",@"21"];      arr = [arr
sortedArrayUsingComparator
:^NSComparisonResult(
NSString*  _Nonnull obj1,
NSString*   _Nonnull obj2
) {        return obj1.
length < obj2.length;    }];    NSLog(@"%@",arr); 打印:2017-11-04 16:41:
22.846
 funTest[2478:150288] (  
  252,    55541,    2295,
     21)

这是一个数组排序的函数。我们经常把在函数中使用函数作为参数称作高阶函数(这实际上就是函数式编程的一种特质)。上面的排序函数中,我们将两个数组内的元素比较的结果拿来使用给我本体函数,实现排序的目的。下面这个函数可能回更加复杂一点:

 NSString *result = 
[self testWithStr:@"adcf"
One:^BOOL(NSString *str)
{return [str
isEqualToString
:@"111"]; } two:^NSString *(BOOL
abool) {  return abool?
@"相等":@"不相等";    }];    NSLog
(@"%@",result);    //打印:    2017-11-08 09:24:49.
011487+0800 funTest[7487
:1779986] 不相等

它是一个字符判断函数,在第一个参数中,我们输入想要比较的字符,在第一个block中进行比较并返回一个bool值,这个bool值将使用在第二个block的参数中,第二个block是根据bool值返回需要比较的两个字符是否相等的描述。
那具体是怎么实现的呢?  根据这个函数的特点,第一个block的调用结果将被用在第二个block上,对于第二个block来讲,他的参数本身就不是固定的,而是由第一个block决定,由此我们应该能想到,第二个block的参数其实就是第一个block才对。实现如下:

- (NSString *)testWithStr
:(NSString *)str  One:
(BOOL(^)(NSString* str))
one two:(NSString*(^)
(BOOL abool))Two{    
return Two(one(str)); }

如果是Swift,其实是及其相似的:

func testWith(Str:String,
one:(String)->Bool,two:
(Bool)->String) -> String
 {        return two(one
 (Str))    }//调用self.testWith
 (Str: "abc", one: { (str
 ) -> Bool in            return str ==
  "123"        }) { (abool) ->
  String in            return abool?
  "相等":"不相等"        }

这里的确是函数式编程, 但是我们发现其中多了东西:虽然这里将一些函数作为另一函数的参数,但是,这些函数的返回值和参数都具有一定的关联,没错,上面的函数中,block one的返回值的类型恰恰是block two的参数类型。他们有一些必然的联系。这就涉及到了响应式编程的范畴,这里其实算是响应式函数编程,不在本文的范畴之内,有兴趣的可以自行了解,本文不做介绍.
但是无可厚非的是,这里我们可以看到函数式编程的特点:将函数做为参数来使用,这就使得函数本身具备更大的灵活性,通过参数函数适应不同的应用场景。
将函数配合泛型,又能继续扩大函数的灵活性。下面修改一下上面的例子看看泛型中的函数式编程:

func testWith<T:Comparable
>(_ obj:T, one:(T)->Bool,
two:(Bool)->String) ->
String {        return
two(one(obj))    }

调用

 let result = tool.
testWith("abc", one:
{ (str) -> Bool in            return str
== "123"        }) { (abool) -
> String in            guard abool
 else{              
 return "不相等"            }          
  return "相等"        }                print(result)                let result2 =
   tool.testWith(5,
   one: { (int) ->
    Bool in            return int
     == 5        }) { (abool)
     -> String in            guard abool
      else{          
      return "不相等"            }          
       return "相等"        }                print(result2)

以上就是函数式编程结合泛型。

提一下我们经常听到的RAC,这是一个响应式函数编程,同时也会使用到泛型。 关于响应式编程, 我会在以后的文章中写出,同时将包含RAC的知识。





以上是关于iOS 中的链式编程函数式编程入门的主要内容,如果未能解决你的问题,请参考以下文章

java链式编程/级联式编程

java之Lambda函数式编程最佳应用举例,链式语法「真干货来拿走」

函数式编程之实践

写 Python 代码不可不知的函数式编程技术

javaScript函数式编程-包含闭包链式优化及柯里化

每日一题 | 函数式编程:1行代码搞定查找最小n个元素