iOS 设计模式,责任链,桥接,适配器,单例,命令

2019-12-22  本文已影响0人  孙掌门

iOS 设计模式,责任链,桥接,适配器,单例,命令

六大设计原则

1. 单一职责原则
2. 依赖倒置原则
3. 开闭原则
4. 里氏替换原则
5. 接口隔离原则
6. 迪米特法则

1.单一职责原则

一个类只负责一件事。

比如系统的 UIView,CALayer,UIView只负责事件的传递和相应,而CALayer只负责动画和显示

2.开闭原则

对修改关闭,对扩展开放。

比如做SDK定义一个类,要考虑他的扩展性,而之后就不需要修改这个类,可以做子类继承等一些事

3.接口隔离原则

使用多个专门的协议,而不是一个庞大的臃肿的协议。

比如UITableView的delegate和DataSource,delegate负责处理回调代理事件,DataSource负责处理数据源

4.依赖倒置原则

抽象不应该依赖具体实现,具体实现可以依赖于抽象。

上层模块不应该依赖于底层模块,他们都应该依赖于抽象,可以看这个解释

5.里氏替换原则

父类可以被子类无缝替换,且原有功能不受任何影响

比如我们系统的KVO,当我们调用addObserver的时候,系统会悄悄的给我们替换成一个添加前缀的类,而我们能感知到的就是使用原有的类。

6.迪米特法则

一个对象应该对其他对象有尽可能少的了解,高内聚,低耦合。

1.责任链

责任链模式其实就是为一个动作,创建一系列可以处理此动作的对象的链,这条链上的每一个对象,都可以去处理这个动作,把发送者和接受者进行解耦,通常每一个接受者都包含另一个接受者的引用,如果这个对象不能处理,就把这个事件传递给下一个接受者,比如我们系统的响应者链。

例子:

//
//  SCXBusiness.h
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
@class SCXBusiness;
typedef void (^complementBlock)(BOOL handled);
typedef void (HandleBlock)(SCXBusiness *handler, BOOL handled);
@interface SCXBusiness : NSObject
// 下一个响应者
@property(nonatomic,strong)SCXBusiness *next;
// 响应者处理方法
- (void)handle:(HandleBlock)handleBLock;
// 各个业务在该方法中做实际的业务处理
- (void)handleBusiness:(complementBlock)completion;

@end

NS_ASSUME_NONNULL_END


//
//  SCXBusiness.m
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import "SCXBusiness.h"

@implementation SCXBusiness
-(void)handle:(HandleBlock)handleBLock{
    complementBlock completion = ^(BOOL handled){
        // 当且业务已经处理
        if (handled) {
            if (handleBLock) {
                handleBLock(self,handled);
            }
        } else {
            // 沿着责任链交给下一个处理者
            if (self.next) {
                [self.next handle:handleBLock];
            } else {
                // 没有业务y处理
                if (handleBLock) {
                    handleBLock(nil,NO);
                }
            }
        }
    };
    [self handleBusiness:completion];
}
-(void)handleBusiness:(complementBlock)completion{
    // 做业务逻辑处理
    // 处理完成之后completion返回.
}
@end


这里我们创建了一个响应者链的类,这个类又引用了它本身,是响应者链的核心,目的是如果当前对象处理不了这个事件,那么由当前对象,传递给下一个对象,让下一个对象来相应,从代码上面看,外面调用handle来处理事件,然后内部调用handleBusiness来进行业务逻辑处理,处理完成之后,调用block返回,来告诉当前对象,是否能完成这个动作,如果当前对应可以完成,饭后当前对象,并且告诉外面handled为yes,如果不可以,那么如果这条链上面,还存在下一个响应者,那么继续向下传递,由下一个响应者来处理,逻辑一样,如果响应者链到头了,说明没有对象相响应。

2.桥接

将抽象部分与他的实现部分隔离,使他们可以独立的变化。

例子:

// 测试类

//
//  SCXBridgeDemo.m
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import "SCXBridgeDemo.h"
#import "SCXObjectA_1.h"
#import "SCXObjectB_2.h"
@interface SCXBridgeDemo()
@property(nonatomic,strong)SCXBaseObjectA *objA;
- (void)handleBusiness;
@end
@implementation SCXBridgeDemo
-(void)handleBusiness{
    SCXObjectA_1 *a1 = [[SCXObjectA_1 alloc] init];
    SCXBaseObjectB *b = [[SCXObjectB_2 alloc] init];
    a1.objB = b;
    [a1 hanldeBusiness];
    
}
@end


// 业务逻辑 A


#import <Foundation/Foundation.h>
#import "SCXBaseObjectB.h"
NS_ASSUME_NONNULL_BEGIN

@interface SCXBaseObjectA : NSObject
// 桥接的核心实现
@property(nonatomic,strong)SCXBaseObjectB *objB;
// 处理业务逻辑
- (void)hanldeBusiness;
@end

NS_ASSUME_NONNULL_END
#import "SCXBaseObjectA.h"

@implementation SCXBaseObjectA
-(void)hanldeBusiness{
    // 1.子类来实现
    // 2.B 继续处理
    // 所以从这里面看出可以有如四种组合,A事件处理有A1和A2,而每一种事件都可以去紧接着处理B1,B2,所以一共有四种
    [self.objB handleBBusiness];
}
@end



// 业务逻辑A的子类A1

#import "SCXBaseObjectA.h"

NS_ASSUME_NONNULL_BEGIN

@interface SCXObjectA_1 : SCXBaseObjectA

@end

NS_ASSUME_NONNULL_END

#import "SCXObjectA_1.h"

@implementation SCXObjectA_1
-(void)hanldeBusiness{
    // 处理事件
}
@end


// 业务逻辑A的子类2


#import "SCXBaseObjectA.h"

NS_ASSUME_NONNULL_BEGIN

@interface SCXObjectA_2 : SCXBaseObjectA

@end

NS_ASSUME_NONNULL_END

#import "SCXObjectA_2.h"

@implementation SCXObjectA_2
-(void)hanldeBusiness{
    // 处理事件
}
@end

// 业务逻辑B


#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SCXBaseObjectB : NSObject
- (void)handleBBusiness;
@end

NS_ASSUME_NONNULL_END
#import "SCXBaseObjectB.h"

@implementation SCXBaseObjectB
-(void)handleBBusiness{
    // 子类来处理
}
@end


// 业务逻辑B的子类1


#import "SCXBaseObjectB.h"

NS_ASSUME_NONNULL_BEGIN

@interface SCXObjectB_1 : SCXBaseObjectB

@end

NS_ASSUME_NONNULL_END


#import "SCXObjectB_1.h"

@implementation SCXObjectB_1
-(void)handleBBusiness{
    // 处理具体事件
}
@end


// 业务逻辑B的子类2

#import "SCXBaseObjectB.h"

NS_ASSUME_NONNULL_BEGIN

@interface SCXObjectB_2 : SCXBaseObjectB

@end

NS_ASSUME_NONNULL_END
#import "SCXObjectB_2.h"

@implementation SCXObjectB_2
-(void)handleBBusiness{
    // 处理具体事件
}
@end


从上面的代码我们可以看出,定义了一个baseA,是用来处理A的业务逻辑,就是业务A可能会存在两种无误逻辑处理,业务B同理,也有两种,这时候我们的产品或者我们的后台可能想通过后台或者某种方式控制,A和B的业务逻辑组合来实现不同的效果,那么我们在bridge里面吗,就可以通过创造不同的对象来实现桥接,这样就可以解决我们的问题了。

我们将业务逻辑A的处理,抽象成1和2,业务B也抽象出来的1和2,也就是说我们将层次结构抽象了出来,将具体的业务逻辑抽象了出来,是得每一个都可以独立变更, 这样就形成了桥接

3.适配器

一个类需要适应变化,适配器使得原本不能在一起工作的类可以一起工作

1. 对象适配器
2. 类适配器

// 对象适配器

//
//  SCXAdapterOri.h
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SCXAdapterOri : NSObject
- (void)hanlde;
@end

NS_ASSUME_NONNULL_END

#import "SCXAdapterOri.h"

@implementation SCXAdapterOri
-(void)hanlde{
    // 原理的处理逻辑
}
@end


\
//
//  SCXAdapterNew.h
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "SCXAdapterOri.h"
NS_ASSUME_NONNULL_BEGIN

@interface SCXAdapterNew : NSObject
@property(nonatomic,strong)SCXAdapterOri *ori;
- (void)handle;
@end

NS_ASSUME_NONNULL_END

#import "SCXAdapterNew.h"

@implementation SCXAdapterNew
-(void)handle{
    [self.ori hanlde];
    // 接着处理现有的逻辑
}
@end



从代码中可以看到,我们有个ori类来处理原来的逻辑,然后我们又创建了一个新的类,来适配原来的类,并调用原来的方法,就形成了最简单的对象适配器。当然还有一种比较好的方式,就是抽象出来协议,用协议的方式来适配,这样代码看起来会更加有层次感,这里暂时不写代码,用上面的简单例子来介绍

4.单例

标准单例方法

//
//  SCXShareInstance.m
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import "SCXShareInstance.h"

@implementation SCXShareInstance
+ (id)shaaredInstance{
    static SCXShareInstance *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone{
    return [self shaaredInstance];
}
-(id)copyWithZone:(NSZone *)zone{
    return self;
}
@end

为了防止外面不通过sharedInstance调用我们的单例类,通过allocwithzone,或者copy的方式创建,我们需要向上面一样去创造一个标准的单例类。

5.命令模式

行为参数化,降低代码重合度,将请求参数化,以便使用不同的请求来参数化其他对象。

例子:

//
//  SCXCommand.h
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
@class SCXCommand;
typedef void (^CompletionBlock)(SCXCommand *command);

@interface SCXCommand : NSObject
@property(nonatomic,copy)CompletionBlock completion;
- (void)execute;
- (void)cancel;
- (void)done;
@end

NS_ASSUME_NONNULL_END


    //
//  SCXCommand.m
//  blogTest
//
//  Created by 孙承秀 on 2019/12/22.
//  Copyright © 2019 孙承秀. All rights reserved.
//

#import "SCXCommand.h"

@implementation SCXCommand
-(void)execute{
    //1.子类实现
    //2.done
    [self done];
}
- (void)cancel{
    self.completion = nil;
}
-(void)done{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.completion) {
            self.completion(self);
        }
        self.completion = nil;
         [[[SCXCommandManager sharedInstace] commands] removeObject:self];
        
    });
}
@end



#import <Foundation/Foundation.h>
#import "SCXCommand.h"
NS_ASSUME_NONNULL_BEGIN

@interface SCXCommandManager : NSObject
// 命令容器
@property(nonatomic,strong)NSMutableArray <SCXCommand *>*commands;
+(instancetype)sharedInstace;
+ (void)executeCommand:(SCXCommand *)cmd completion:(CompletionBlock)completion;
+ (void)cancelCommand:(SCXCommand *)cmd;
@end

NS_ASSUME_NONNULL_END


#import "SCXCommandManager.h"

@implementation SCXCommandManager
+(void)executeCommand:(SCXCommand *)cmd completion:(CompletionBlock)completion{
    if (cmd) {
        if (![self _isExecutingCommand:cmd]) {
            [[[self sharedInstace] commands] addObject:cmd];
            cmd.completion = completion;
            [cmd execute];
        }
    }
}
+(void)cancelCommand:(SCXCommand *)cmd{
    if (cmd) {
        [[[self sharedInstace] commands] removeObject:cmd];
        [cmd cancel];
    }
}
+ (BOOL)_isExecutingCommand:(SCXCommand *)cmd{
    if (cmd) {
        NSArray *arrs = [[self sharedInstace] commands];
        if ([arrs containsObject:cmd]) {
            return YES;
        }
    }
    return NO;
}

@end

从代码上面看,我们建立了一个命令类,命令可以运行和取消,当完成之后,用回调告诉外界,命令执行完毕,我们的manager是来管理命令的,可以执行命令,但我们执行命令的时候,会先判断是否有命令和是否正在执行命令,也就是是否在命令数组中,如果在说明正在执行,然后经命令添加到容器中,炳设置回调,然后做命令的执行,这就是命令的运行,命令的取消就是调用命令的取消操作然后从数组中执行,这样就将我们的命令这一个大操作参数化了,同样上面的代码可以抽象出一个协议类,将上面的command继承自一个协议就可以了,这样就可以有多个命令,他们继承自一个协议,而这个协议里面有运行和取消就可以了,然后管理类,不管你添加什么命令,继承自命令协议就可以了,然后去执行和操作,这样我们代码可维护性和扩展性,有提高了一个档次,这里做简单介绍就不写代码了,我想大家应该能明白我的意思。

上一篇下一篇

猜你喜欢

热点阅读