iOS:组件化之Target-Action模式

传统模式的弊端

传统模式的组件之间的交互都是#import "HomeVC.h",然后在该页面push或者present,项目小没有问题。但是当项目越来越大,就会发现:

  1. 模块间相互依赖,耦合严重
  2. 管理起来很混乱

如下图:
png1

任何一个模块变动,导致其他依赖该模块的地方需要检查是否要随着变动。

那么按照解耦的思想,改成如下这种中心化的方式就会清晰明了

png2

但是依然有问题。虽然看起来比刚开始清晰了很多,但是每个组件还是和中间层双向依赖

双向依赖:如果首页或者登陆改变,导致依赖这两个模块的中间层可能也需要改变,还是具有耦合性,只是低了一些

所以target-action设计模式就解决了这些问题

png3

我们把这里的中间层叫做Mediator
但是有几个问题需要这个设计模式处理:

  1. Mediator如何找到并调用组件
  2. 相互独立的组件如何调用其他组件的方法

首先每个模块需要配置Target和Category,其中Target是每个组件对应一个或者多个Target,Target可以引用和依赖组件,Category是MEdiator的分类,使用分类是为了让Mediator中的业务代码分离,不然所有代码在Mediator中会导致其臃肿

1. Mediator如何找到组件、调用组件

Target中引用了组件,所以Mediator找到target就可以了,Category利用runtime的API,通过字符串的形式创建Target对象,以及创建Selector,再把Target和Selector交由Mediator主类去调用Action
png4

大概目录结构如下图:
jpg1

Demo演示

//OBMediator.h
@interface OBMediator : NSObject
+(OBMediator *)shared;

- (void)performTarget:(NSString *)targetName Action:(NSString *)actionName Params:(NSDictionary *)parmas;

@end

//OBMediator.m
#import "OBMediator.h"
#import "ViewController.h"
//#import "PersonalVC.h"

@implementation OBMediator
+(OBMediator *)shared {
    static OBMediator *mediator = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mediator = [[OBMediator alloc] init];
    });
    return mediator;
}
- (void)performTarget:(NSString *)targetName Action:(NSString *)actionName Params:(NSDictionary *)parmas {
    
    Class cls = NSClassFromString(targetName);
    NSObject *target = [[cls alloc] init];
    SEL sel = NSSelectorFromString(actionName);
    if (![target respondsToSelector:sel]) {
        NSLog(@"未知错误");
        return ;
    }
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [target performSelector:sel withObject:parmas];
}
@end

target

@interface Target_Personal : NSObject

@end


#import "Target_Personal.h"
#import "PersonalVC.h"

@implementation Target_Personal


- (void)pushToPersonalVCWithParams:(NSDictionary *)parmas {
    
    PersonalVC * vc =[[PersonalVC alloc] init];
    [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:vc animated:YES completion:nil];
}

@end

OBMediator+Personal.h类中的实现

// OBMediator+Personal.h
#import "OBMediator.h"
@interface OBMediator (Personal)

- (void)openPersonalVCWithParams:(NSDictionary *)parmas;

@end

//OBMediator+Personal.m
#import "OBMediator+Personal.h"
NSString * const PersonalTarget = @"Target_Personal";
NSString * const ActionPushPersonal = @"pushToPersonalVCWithParams:";

@implementation OBMediator (Personal)


- (void)openPersonalVCWithParams:(NSDictionary *)parmas {
	//内部通过Target_Personal字符串找到该对象,执行他的selector,就是找到最终的跳转代码
    [self performTarget:PersonalTarget Action:ActionPushPersonal Params:parmas];
    
}
@end

调用时需要引入OBMediator+Personal.h

#import "OBMediator+Personal.h"

- (void)click {
    [[OBMediator shared] openPersonalVCWithParams:@{@"key":@"value"}];
}

Target-Action方案的优点。
  1. 解耦:只存在组件依赖Mediator中介的这一层依赖关系。
  2. Target-Action方案也能有一定的安全保证,它对URL中的Native前缀进行安全验证。因此,Target-Action方案不管从维护性、可读性、扩展性来说,都是一个比较完美的方案。
  3. 统一处理所有组件间调用入口,方便管理:都是调用“performTarget: action: params: shouldCacheTarget:”方法。第三个参数是一个字典,这个字典里面可以传很多参数,只要Key-Value写好就可以了。
    Target-Action方案处理错误的方式也统一在一个地方了,Target没有,或者是Target无法响应的Action方法,都可以在Mediator这里进行统一出错处理。
Target-Action方案的缺点
  1. 每个组件的Category对应一个Target类,Categroy中的Action方法对应Target类中的Action场景。代码量增多
  2. 伪解耦,通过字符串的方式来创建实例,依赖各种定义的String,维护String
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值