美文网首页ZJ_iOS面试iOS DeveloperiOS 进阶
iOS关于面向接口编程的思考

iOS关于面向接口编程的思考

作者: Mr_Butterfly | 来源:发表于2017-04-20 02:34 被阅读193次

    前言

    曾经做java开发时,接触到很多编程思想、设计模式,后来转向iOS后,常常会思考如何将这些知识融入到iOS开发当中。今天想分享的就是在java当中无处不在,但是在OC中却很少被提及到的概念——面向接口编程。

    什么是接口

    接口的特征为:只声明方法,不实现方法。简单来说,接口是某些行为的抽象表达,也是一组协议或约定,我们不关心某个具体类,而只关心这个类是否遵守并实现了这些约定。例如飞机和鸟,都有共同的一种行为:飞。因为飞机和鸟并没有相同的父类可以继承(关于抽象类和接口区别以及使用场景,有兴趣的小伙伴可以google一下,很多文章分析的很透彻了,这里我就不在赘述。),因此我们就可以抽象出一个接口类IFly,与java不同的是,iOS使用protocol关键字来定义接口。

    @protocol IFly <NSObject>
    
    - (void)fly;
    
    @end
    

    飞机的实现类

    Plane.h

    @interface Plane : NSObject <IFly>
    
    @end
    

    Plane.m

    @implementation Plane
    
    - (void)fly
    {
        NSLog(@"飞机飞");
    }
    
    @end
    

    鸟的实现类

    Bird.h

    @interface Bird : NSObject <IFly>
    
    @end
    

    Bird.m

    @implementation Bird
    
    - (void)fly
    {
        NSLog(@"小鸟飞");
    }
    
    @end
    

    使用方法:

    id<IFly> flyBehaviour = [Plane new];
    [flyBehaviour fly];
    flyBehaviour = [Bird new];
    [flyBehaviour fly];
    

    控制台打印:

    IOPDemo[20101:1939006] 飞机飞
    
    IOPDemo[20101:1939006] 小鸟飞
    

    只要将flyBehaviour指向不同的实现了IFly接口的对象,就能体现出不同的具体行为,这也是多态的表现形式。

    面向接口编程的好处

    设计模式原则中有一点:依赖倒置原则。即

    1. 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
    2. 抽象不应该依赖细节;
    3. 细节应该依赖抽象;

    面向接口编程可以很好地遵守这个设计模式原则。以上例子中,抽象就是指IFly类,细节就是指Plane或Bird这样的具体类。这样做的好处是可以降低类与类之间的耦合,易于程序扩展,可以在不破坏上层代码的情况下修改甚至替换整个底层代码。面向接口编程还有其他好处:

    • 可以在代码运行期间,动态地修改类的行为。在不同的条件下,由高层模块决定使用哪个具体类。
    • 并行开发。在定义接口之后,业务开发人员只需调用接口方法而不用关心这些方法是否已经实现,而底层开发人员则可以根据需求逐步完善具体类的代码。
    • 便于单元测试。封装性越好的代码,越容易测试。面向接口编程可以很好的将业务代码模块化,从而针对不同的逻辑进行测试。
    • 有更多的好处,希望大家可以在使用过程当中去感受。

    再举个简单的例子。当移动端和服务端协商了网络请求以及返回值的参数,即使服务端的接口并没有完成,也不影响移动端的开发人员进行开发,同时移动端开发人员也并不关心后台逻辑如何变化,只需保证入参及出参的正确性即可。

    iOS编程中使用接口

    首先看一下项目大致结构:


    结构图.png

    service是ViewController中的一个接口属性,InterfaceService是实现了InterfaceProtocol协议的实现类。在页面调用service的方法时,实际是调用了InterfaceService这个实现类的方法,在实现类中可以使用很多第三方的网络请求框架,如HYB,YTK等等。这些第三方库是基于AF进行了二次封装,优点是可以将请求的逻辑统一,减少上层的代码量,甚至替换掉底层AF,更换其他框架。最后AF请求服务器,并将数据一层一层向上传递直至ViewController。

    那么相比于直接在ViewController中调用HYB或者YTK的网络请求,中间多的一层InterfaceService优点是什么呢?

    在我们公司目前有很多业务模块如任务模块,商城模块等等。不同的业务模块有不同的服务器地址,不同的服务器请求参数形式也都不一样。如果在VC层中直接调用第三方网络请求,那么就会造成很多的重复判断代码。因此增加的InterfaceService又称为业务请求层,在这一层的代码中,我可以针对不同的服务器统一管理域名,请求配置或请求方式,编写VC的业务开发人员只需传递业务所需要的关键参数如id,分页参数等等,同时通过回调拿到网络请求的返回值,而不用关心底层如何实现,并行开发提高开发效率,也利于编写业务请求层的开发人员进行单元测试。

    下面是主要类的截图


    项目目录结构.png

    接口文件 InterfaceProtocol.h

    @protocol InterfaceProtocol <NSObject>
    
    @optional
    
    
    /**
     获取首页数据
    
     @param param 请求参数
     @param complete 成功回调
     @param failed 失败回调
     */
    - (void)fetchData:(NSDictionary *)param complete:(void (^)(NSDictionary *response))complete failed:(void (^)(NSString *error))failed;
    
    @end
    

    接口实现类 InterfaceService.h

    @interface InterfaceService : NSObject <InterfaceProtocol>
    
    @end
    

    接口实现类 InterfaceService.m

    #import "InterfaceService.h"
    
    @implementation InterfaceService
    
    - (void)fetchData:(NSDictionary *)param complete:(void (^)(NSDictionary *response))complete failed:(void (^)(NSString *error))failed
    {
        if (param[@"id"]) {
            //模拟网络请求返回成功
            complete(@{@"status":@"success"});
        } else {
            //模拟网络请求返回失败
            failed(@"error");
        }
        
    }
    
    @end
    

    ViewController中的代码

    #import "ViewController.h"
    #import "InterfaceProtocol.h"
    #import "InterfaceService.h"
    
    @interface ViewController ()
    
    @property (nonatomic, strong) id<InterfaceProtocol> service;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        //接口指向一个实现类
        //其实这边可以使用DI注入
        self.service = [InterfaceService new];
        //发起一个请求
        [self.service fetchData:@{@"id":@"1"} complete:^(NSDictionary *response) {
            NSLog(@"do sth...");
        } failed:^(NSString *error) {
            NSLog(@"%@",error);
        }];
    }
    
    
    @end
    

    结束语

    在今后的学习过程当中,我会继续尝试在项目里结合更多的元素,设计出更好的代码。

    小伙伴们如果有好的想法可以一起讨论,以上有不足或者错误的地方,欢迎提出,我会认真回复。

    相关文章

      网友评论

        本文标题:iOS关于面向接口编程的思考

        本文链接:https://www.haomeiwen.com/subject/dcxkzttx.html