iOS面试总结

iOS常用设计模式详解

2016-02-17  本文已影响0人  AKyS佐毅

1、设计原则

前面五种被称为面向对象设计中常用的SOLID原则。

1、责任链模式

举例iOS事件分发和相应:

1.在iOS视图树形结构中找到最终的接收者,也就是触摸事件发生的那个最上层的View上,这一过程称为hit-testing(测试命中),通过一层层的遍历找到最终的命中视图称为hit-test view.
UIView中有两个方法用来确定hit-test view.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

从apple官方文档里面的截图,这里所有的显示的View都是加载到主window上,假设我们触摸到屏幕上ViewD的区域,当我们没有重载UIView的hitTest:withEvent:和pointInside:withEvent:这两个方法时,系统默认的处理如下:

响应事件。说明一下,对于触摸事件来说,无论View是否处理事件,即使是application通过[application beginIgnoringInteractionEvents]忽略了触摸事件,上面hit-testing的过程依然存在,它只影响第二个步骤事件响应的过程。下面我们将介绍iOS响应者链条(Responder chain)

从官方文档里面截取的一张关于响应者链条的截图。我们先看上图左边的情况:标注为①的地方即为步骤1找到的hit-test view 它作为第一响应者来响应这个事件,如果该view没有通过重写或者封装touch系列方法来处理该事件,默认touch的实现就是调用父类的touch方法,将事件传递下去。在这里由1->传递到它的父类2,2是控制器的根view,->传递到vc控制器->传递到窗口window->传递到application

再看上图右边的情况:标注为①的地方即为步骤1找到的hit-test view,同时它是控制器的根view并且还有父视图,事件传递到控制器->再传递到父视->传递到控制器,再传递到父视图窗口->application。其实上图左边部分也可以理解为窗口是控制器根视图的父视图。如果整个响应者链条结束,都没有对事件做处理,那么该事件会被丢弃。

扩展说明:

如何控制控件的点击区域

1.1、责任链模式实战

我们假设第一个对象不处理,然后让第二个去处理。如上所述。

在举个例子

#import <Foundation/Foundation.h>

@protocol Leave <NSObject>

- (void)handleLeaveApplication:(NSUInteger)dayCount;

@end

@interface Manager : NSObject<Leave>

@property (nonatomic, strong) id<Leave> superior;

@end

@implementation Manager

- (void)handleLeaveApplication:(NSUInteger)dayCount {
}

@end

@interface PM : Manager

@end

@implementation PM

- (void)handleLeaveApplication:(NSUInteger)dayCount {

    if (dayCount < 10) {
        NSLog(@"dayCount:%ld----PM:请假跟女朋友去旅游啊,调试完这个bug就走吧。过来你看,你的程序报错了:\"找不到对象\"", dayCount);
    } else {
        if (self.superior != nil) {
            NSLog(@"dayCount:%ld----PM:请假跟女朋友去旅游啊,我没权利批假,去问一下我的老大吧", dayCount);
            [self.superior handleLeaveApplication:dayCount];
        }
    }
}

@end

@interface CTO : Manager

@end

@implementation CTO

- (void)handleLeaveApplication:(NSUInteger)dayCount {
    if (dayCount < 10) {
        NSLog(@"CTO:我很忙,这种小事别烦我");
        return;
    }
    if (dayCount < 20) {
        NSLog(@"dayCount:%ld----CTO:又请假相亲啊,去吧去吧~", dayCount);
    } else {
        if (self.superior != nil) {
            NSLog(@"dayCount:%ld----CTO:又请假相亲啊,我没权利批假,去问一下我的老大吧~", dayCount);
            [self.superior handleLeaveApplication:dayCount];
        }
    }
}

@end

@interface CEO : Manager

@end

@implementation CEO

- (void)handleLeaveApplication:(NSUInteger)dayCount {
    if (dayCount < 20) {
        NSLog(@"CEO:我很忙去找你上司");
        return;
    }
    if (dayCount < 30) {
        NSLog(@"dayCount:%ld----CEO:Bug都写完了吗?那就去吧", dayCount);
    } else {
        NSLog(@"dayCount:%ld----CEO:世界那么大你是不是也想出去看看?回去写你的Bug", dayCount);
    }
}

@end

void chainOfResponsibility() {
    CEO *ceo = [[CEO alloc] init];
    CTO *cto = [[CTO alloc] init];
    PM *pm = [[PM alloc] init];
    pm.superior = cto;
    cto.superior = ceo;
    
    NSArray *leaveApplicationArray = @[@"1", @"16", @"25", @"31"];
    for (NSString *string in leaveApplicationArray) {
        [pm handleLeaveApplication:[string integerValue]];
    }
}

2、桥接模式


 /**
  *  桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
  *  在本例中,AbstractRemoteControl是抽象部分,TVProtocol是其实现部分。
  *  抽象部分与实现部分通过detectTVFunction方法来连接。
  */
  
@protocol TVProtocol <NSObject>

@required

- (void)switchChannel; // 切换频道

- (void)adjustVolume;  // 调节音量

- (void)powerSwitch;   // 电源开关

@end

---------------------------------------------------------------
#import "TVProtocol.h"
@interface AbstractRemoteControl : NSObject

@property (nonatomic, weak) id<TVProtocol> tvProtocol;

- (void)detectTVFunction;

@end

---------------------------------------------------------------
@implementation AbstractRemoteControl

- (void)detectTVFunction {
    NSLog(@"检测电视机具备的功能,由子类来进行实现");
}

@end

---------------------------------------------------------------
@interface ConcreteRemoteControl : AbstractRemoteControl

// 重写该方法
- (void)detectTVFunction;

@end

---------------------------------------------------------------
@implementation ConcreteRemoteControl

- (void)detectTVFunction {
    [self.tvProtocol switchChannel];
    [self.tvProtocol adjustVolume];
    [self.tvProtocol powerSwitch];
}

@end

---------------------------------------------------------------
#import "TVProtocol.h"
@interface AbstractTV : NSObject <TVProtocol>

@end

---------------------------------------------------------------
@implementation AbstractTV

- (void)switchChannel {
    NSLog(@"切换频道,由具体的子类来实现");
}

- (void)adjustVolume {
    NSLog(@"调节音量,由具体的子类来实现");
}

- (void)powerSwitch {
    NSLog(@"电源开关,由具体的子类来实现");
}

@end

---------------------------------------------------------------

@interface TVA : AbstractTV

// 重写这三个方法
- (void)switchChannel;
- (void)adjustVolume;
- (void)powerSwitch;

@end

---------------------------------------------------------------
@implementation TVA

- (void)switchChannel {
    NSLog(@"电视机A 具备了切换频道的功能");
}

- (void)adjustVolume {
    NSLog(@"电视机A 具备了调节音量的功能");
}

- (void)powerSwitch {
    NSLog(@"电视机A 具备了电源开关的功能");
}

@end
---------------------------------------------------------------
@interface TVB : AbstractTV

// 重写这三个方法
- (void)switchChannel;
- (void)adjustVolume;
- (void)powerSwitch;

@end

---------------------------------------------------------------
@implementation TVB

- (void)switchChannel {
    NSLog(@"电视机B 具备了切换频道的功能");
}

- (void)adjustVolume {
    NSLog(@"电视机B 具备了调节音量的功能");
}

- (void)powerSwitch {
    NSLog(@"电视机B 具备了电源开关的功能");
}

@end

---------------------------------------------------------------

AbstractRemoteControl *remoteControl = [[ConcreteRemoteControl alloc] init];
TVProtocol tvProtocol = [[TVA alloc] init];
remoteControl.tvProtocol = tvProtocol;

[remoteControl detectTVFunction];

NSLog(@"///////////////////////////////");

tvProtocol = [[TVB alloc] init];
remoteControl.tvProtocol = tvProtocol;
[remoteControl detectTVFunction];

桥接模式在UIKit和Foundation中的使用场景,比如,同一界面中在不同的用户等级(如游客模式、普通用户、VIP)时,展示不同的板块

3、适配器模式

@interface Target : NSObject

- (void)operation;

@end
---------------------------------------------------------------
@implementation Target

- (void)operation{
    // 原有的具体业务逻辑
}
@end
---------------------------------------------------------------
// 适配对象
@interface CoolTarget : NSObject

// 被适配对象
@property (nonatomic, strong) Target *target;

// 对原有方法包装
- (void)request;

@end
---------------------------------------------------------------
@implementation CoolTarget

- (void)request{
    // 额外处理
    
    [self.target operation];
    
    // 额外处理
}
@end

4、单例模式

@interface Mooc : NSObject

+ (id)sharedInstance;

@end
---------------------------------------------------------------
@implementation Mooc

+ (id)sharedInstance{
    // 静态局部变量
    static Mooc *instance = nil;
    
    // 通过dispatch_once方式 确保instance在多线程环境下只被创建一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 创建实例
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}

// 重写方法【必不可少】
+ (id)allocWithZone:(struct _NSZone *)zone{
    return [self sharedInstance];
}

// 重写方法【必不可少】
- (id)copyWithZone:(nullable NSZone *)zone{
    return self;
}

@end

4、命令模式

@class Command;
typedef void(^CommandCompletionCallBack)(Command* cmd);

@interface Command : NSObject
@property (nonatomic, copy) CommandCompletionCallBack completion;

- (void)execute;
- (void)cancel;

- (void)done;

@end
---------------------------------------------------------------
@implementation Command

- (void)execute{
    
    //override to subclass;
    
    [self done];
}

- (void)cancel{
    
    self.completion = nil;
}

- (void)done{
    dispatch_async(dispatch_get_main_queue(), ^{
        
        if (_completion) {
            _completion(self);
        }
        
        //释放
        self.completion = nil;
        
        [[CommandManager sharedInstance].arrayCommands removeObject:self];
    });
}

@end
---------------------------------------------------------------
@interface CommandManager : NSObject
// 命令管理容器
@property (nonatomic, strong) NSMutableArray <Command*> *arrayCommands;

// 命令管理者以单例方式呈现
+ (instancetype)sharedInstance;

// 执行命令
+ (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion;

// 取消命令
+ (void)cancelCommand:(Command *)cmd;

@end
---------------------------------------------------------------
@implementation CommandManager

// 命令管理者以单例方式呈现
+ (instancetype)sharedInstance{
    static CommandManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}

// 【必不可少】
+ (id)allocWithZone:(struct _NSZone *)zone{
    return [self sharedInstance];
}

// 【必不可少】
- (id)copyWithZone:(nullable NSZone *)zone{
    return self;
}

// 初始化方法
- (id)init{
    self = [super init];
    if (self) {
        // 初始化命令容器
        _arrayCommands = [NSMutableArray array];
    }
    return self;
}

+ (void)executeCommand:(Command *)cmd completion:(CommandCompletionCallBack)completion{
    if (cmd) {
        // 如果命令正在执行不做处理,否则添加并执行命令
        if (![self _isExecutingCommand:cmd]) {
            // 添加到命令容器当中
            [[[self sharedInstance] arrayCommands] addObject:cmd];
            // 设置命令执行完成的回调
            cmd.completion = completion;
            //执行命令
            [cmd execute];
        }
    }
}

// 取消命令
+ (void)cancelCommand:(Command *)cmd{
    if (cmd) {
        // 从命令容器当中移除
        [[[self sharedInstance] arrayCommands] removeObject:cmd];
        // 取消命令执行
        [cmd cancel];
    }
}

// 判断当前命令是否正在执行
+ (BOOL)_isExecutingCommand:(Command *)cmd{
    if (cmd) {
        NSArray *cmds = [[self sharedInstance] arrayCommands];
        for (Command *aCmd in cmds) {
            // 当前命令正在执行
            if (cmd == aCmd) {
                return YES;
            }
        }
    }
    return NO;
}

@end

再举一个点餐的例子

执行指令

@protocol CommandProtocol <NSObject>

@required

- (void)execute;

@end

服务员


@interface Waiter : NSObject

/**
 点菜
 */
- (void)addOrder:(id <CommandProtocol>)command;

/**
 全点好了
 */
- (void)submmitOrder;

/**
 取消菜
 */
- (void)cancleOrder:(id <CommandProtocol>)command;

@end

@interface Waiter()

@property (nonatomic, strong) NSMutableArray *commandQueue;

@end

@implementation Waiter

- (instancetype)init {
    if (self = [super init]) {
        self.commandQueue = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)addOrder:(id <CommandProtocol>)command {
    [_commandQueue addObject:command];
}

- (void)submmitOrder {
    for (id <CommandProtocol> command in _commandQueue) {
        [command execute];
    }
    [_commandQueue removeAllObjects];
}

- (void)cancleOrder:(id <CommandProtocol>)command {
    if ([_commandQueue containsObject:command]) {
        [_commandQueue removeObject:command];
        NSLog(@"取消成功");
    } else {
        NSLog(@"已经不可以取消了");
    }
}

@end

厨子

@interface Cook : NSObject

/**
 制作龙虾
 */
- (void)cookLobster;

/**
 制作鲍鱼
 */
- (void)cookAbalone;

@end

@implementation Cook

- (void)cookLobster {
    NSLog(@"制作好了龙虾");
}
- (void)cookAbalone {
    NSLog(@"制作好了鲍鱼");
}

@end
@interface Command : NSObject<CommandProtocol>

@property (nonatomic, strong, readonly) Cook *cook;

- (instancetype)initWithReceiver:(Cook *)cook;

@end

@implementation Command

- (void)execute {
}

- (void)cancleCommand {
}

- (instancetype)initWithReceiver:(Cook *)cook {
    if (self = [super init]) {
        _cook = cook;
    }
    return self;
}

@end

龙虾


@interface LobsterCommand : Command

@end

@implementation LobsterCommand

- (void)execute {
    [self.cook cookLobster];
}

@end

鲍鱼

@interface AbaloneCommand : Command

@end

@implementation AbaloneCommand

- (void)execute {
    [self.cook cookAbalone];
}

@end

5、中介者模式(Mediator)

@protocol MediatorProtocol <NSObject>

- (void)showMessage:(NSString *)message;

@end
--------------------------------------------------------------------------------------

@interface ChatRoom : NSObject<MediatorProtocol>

- (void)showMessage:(NSString *)message userName:(NSString *)name;

@end

@implementation ChatRoom

- (void)showMessage:(NSString *)message {
    NSLog(@"%@\n",message);
}

- (void)showMessage:(NSString *)message userName:(NSString *)name {
    NSString *string = [NSString stringWithFormat:@"%@:%@", name, message];
    [self showMessage:string];
}

@end
--------------------------------------------------------------------------------------

@interface User : NSObject

- (instancetype)initWithName:(NSString *)name room:(ChatRoom *)room;

- (void)sendMessage:(NSString *)message;

@end

@interface User()

@property (nonatomic, copy) NSString *name;     ///< 用户昵称
@property (nonatomic, strong) ChatRoom *room;   ///< 当前聊天室

@end

@implementation User

- (instancetype)initWithName:(NSString *)name room:(ChatRoom *)room {
    if (self = [super init]) {
        _name = name;
        _room = room;
    }
    return self;
}

- (void)sendMessage:(NSString *)message {
    [_room showMessage:message userName:_name];
}

@end

void mediator() {
    ChatRoom *room = [[ChatRoom alloc] init];
    User *wuJun = [[User alloc] initWithName:@"吴军" room:room];
    User *me = [[User alloc] initWithName:@"SuperMario" room:room];
    [wuJun sendMessage:@"来自硅谷的第一封信"];
    [me sendMessage:@"谢谢,不做伪工作者"];
}

6、观察者模式(Observer)

@protocol SubjectProtocol <NSObject>

- (void)addObserver:(id <ObserverProtocol>)observer;
- (void)removeObserver:(id <ObserverProtocol>)observer;
- (void)notify;

@end
--------------------------------------------------------------------------------------
@interface JobProvider : NSObject<SubjectProtocol>

@end

@interface JobProvider()

@property (nonatomic, strong) NSMutableArray *observers;

@end

@implementation JobProvider

- (void)addObserver:(NSObject *)observer {
    [self.observers addObject:observer];
}
- (void)removeObserver:(NSObject *)observer {
    [self.observers removeObject:observer];
}
- (void)notify {
    for (id <ObserverProtocol> observer in self.observers) {
        [observer update];
    }
}

- (NSMutableArray *)observers {
    if (!_observers) {
        _observers = [[NSMutableArray alloc] init];
    }
    return _observers;
}

@end
--------------------------------------------------------------------------------------

@protocol ObserverProtocol <NSObject>

- (void)update;

@end
--------------------------------------------------------------------------------------

@interface JobHunter : NSObject<ObserverProtocol>

- (instancetype)initWithName:(NSString *)name;

@end

@interface JobHunter()

@property (nonatomic, copy) NSString *name;

@end

@implementation JobHunter

- (instancetype)initWithName:(NSString *)name {
    if (self = [super init]) {
        _name = name;
    }
    return self;
}


- (void)update {
    NSLog(@"%@:有一个新的职位更新啦",_name);
}

@end

7、备忘录模式(Memento)

@interface EditorMemento : NSObject

@property (nonatomic, copy, readonly) NSArray *array;
- (instancetype)initWithArray:(NSArray *)array;

@end

@implementation EditorMemento

- (instancetype)initWithArray:(NSArray *)array {
    if (self = [super init]) {
        _array = array;
    }
    return self;
}

@end
--------------------------------------------------------------------------------------

@class EditorMemento;
@interface Editor : NSObject

- (void)insertContent:(NSString *)string;
- (EditorMemento *)save;
- (void)echo;
- (void)restore:(EditorMemento *)memento;

@end

@interface Editor()

@property (nonatomic, strong) NSMutableArray *array;
@property (nonatomic, strong) EditorMemento *memento;

@end

@implementation Editor

- (instancetype)init {
    if (self = [super init]) {
        _array = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)insertContent:(NSString *)string {
    [_array addObject:string];
}

- (EditorMemento *)save {
    return [[EditorMemento alloc] initWithArray:[_array copy]];
}

- (void)echo {
    for (NSString *string in _array) {
        NSLog(@"%@", string);
    }
}

- (void)restore:(EditorMemento *)memento {
    _array = [[NSMutableArray alloc] initWithArray:memento.array];
}

- (EditorMemento *)memento {
    if (!_memento) {
        _memento = [[EditorMemento alloc] initWithArray:[_array copy]];
    }
    return _memento;
}

@end
--------------------------------------------------------------------------------------
void memento() {
    Editor *editor = [[Editor alloc] init];
    [editor insertContent:@"总熬夜会带来三个问题"];
    [editor insertContent:@"第一:记忆力会明显下降"];
    [editor insertContent:@"第二:数数经常会数错"];
    EditorMemento *memento = [editor save];
    [editor insertContent:@"第四:记忆力会明显下降"];
    [editor echo];
    NSLog(@"//------------------------------------");
    [editor restore:memento];
    [editor echo];
}

8、策略模式(Strategy):

@protocol StrategyProtocol <NSObject>

+ (void)sort:(NSArray *)array;

@end
--------------------------------------------------------------------------------------

@interface BubbleSortStrategy : NSObject<StrategyProtocol>

@end

@implementation BubbleSortStrategy

+ (void)sort:(NSArray *)array {
    NSLog(@"Array's count=%ld, 使用了冒泡排序", array.count);
}

@end
--------------------------------------------------------------------------------------

@interface QuickSortStrategy : NSObject<StrategyProtocol>

@end

@implementation QuickSortStrategy

+ (void)sort:(NSArray *)array {
    NSLog(@"Array's count=%ld, 使用了快速排序", array.count);
}

@end
--------------------------------------------------------------------------------------

@interface Sort : NSObject<StrategyProtocol>

@end

@implementation Sort

+ (void)sort:(NSArray *)array {
    if (array.count > 5) {
        [QuickSortStrategy sort:array];
    } else {
        [BubbleSortStrategy sort:array];
    }
}

@end

9、访问者模式(Visitor)

@protocol PersonProtocol <NSObject>

- (void)accept:(id <ActionProtocol>)visitor;

@end
--------------------------------------------------------------------------------------

@interface PositivePerson : NSObject<PersonProtocol>

@end

@implementation PositivePerson

- (void)accept:(id <ActionProtocol>)visitor {
    [visitor positiveConclusion:[[PositivePerson alloc] init]];
}

@end
--------------------------------------------------------------------------------------

@interface NegativePerson : NSObject<PersonProtocol>

@end

@implementation NegativePerson

- (void)accept:(id <ActionProtocol>)visitor {
    [visitor negativeConclusion:[[NegativePerson alloc] init]];
}

@end

@protocol PersonProtocol;
--------------------------------------------------------------------------------------

@protocol ActionProtocol <NSObject>

- (void)positiveConclusion:(id <PersonProtocol>)positive;
- (void)negativeConclusion:(id <PersonProtocol>)negavite;

@end
--------------------------------------------------------------------------------------

@interface HalfCupWater : NSObject<ActionProtocol>

@end

@implementation HalfCupWater

- (void)positiveConclusion:(id <PersonProtocol>)positive {
    NSLog(@"乐观的人:还有半杯水可以喝");
}
- (void)negativeConclusion:(id <PersonProtocol>)negavite {
    NSLog(@"悲观的人:只剩半杯水了啊");
}

@end
--------------------------------------------------------------------------------------

@interface ObjectStructure : NSObject

- (void)add:(id <PersonProtocol>)person;
- (void)remove:(id <PersonProtocol>)person;
- (void)echo:(id <ActionProtocol>)action;

@end

@interface ObjectStructure()

@property (nonatomic, strong) NSMutableArray <PersonProtocol> *array;

@end

@implementation ObjectStructure

- (instancetype)init {
    if (self = [super init]) {
        _array = [[NSMutableArray <PersonProtocol> alloc] init];
    }
    return self;
}

- (void)add:(id <PersonProtocol>)person {
    [_array addObject:person];
}

- (void)remove:(id <PersonProtocol>)person {
    [_array removeObject:person];
}

- (void)echo:(id <ActionProtocol>)action {
    for (id <PersonProtocol>person in _array) {
        [person accept:action];
    }
}

@end

10、模板方法模式(TemplateMethod)

@protocol PublishProtocol <NSObject>

- (void)code;
- (void)test;
- (void)pack;
- (void)upload;

@end
--------------------------------------------------------------------------------------

@interface Publish : NSObject<PublishProtocol>

- (void)publish;

@end

@implementation Publish

- (void)publish {
    [self code];
    [self test];
    [self pack];
    [self upload];
}

- (void)code {
}
- (void)test {
}
- (void)pack {
}
- (void)upload {
}
@end
--------------------------------------------------------------------------------------

@interface iOSPublish : Publish

@end

@implementation iOSPublish

- (void)code {
    NSLog(@"编写iOS代码");
}
- (void)test {
    NSLog(@"测试iOS代码");
}
- (void)pack {
    NSLog(@"xcode archive");
}
- (void)upload {
    NSLog(@"上传到AppStore");
}

@end
--------------------------------------------------------------------------------------

@interface AndroidPublish : Publish

@end

@implementation AndroidPublish

- (void)code {
    NSLog(@"编写Android代码");
}
- (void)test {
    NSLog(@"测试Android代码");
}
- (void)pack {
    NSLog(@"混淆代码,打包");
}
- (void)upload {
    NSLog(@"上传到各种应用商店");
}

@end
上一篇下一篇

猜你喜欢

热点阅读