美文网首页面试专题(重难点)
iOS中常用的几种设计模式

iOS中常用的几种设计模式

作者: 清风_____ | 来源:发表于2021-03-25 15:39 被阅读0次
    1.代理模式

    代理模式完成委托方交给的任务,委托方有一些任务自己不想完成,但是还需要要实现,则将该任务存放到协议中,由代理完成.但是代理并不会主动的执行任务,需要委托方通知代理。

    • 1.1应用场景
      当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。

    • 1.2优势
      解耦合

    • 1.3敏捷原则
      开放-封闭原则

    • 1.4实例
      tableview的 数据源delegate,通过和protocol的配合,完成委托诉求。列表row个数delegate,自定义的delegate。

    /*实现
    说明:代理是一对一的,响应栈内最近一个代理对象(多为传值,相连的页面)
    代理的使用,可以简单的概括为两个三步走,即创建代理的三步和使用代理的三步。 
    1.创建代理:
    2.创建代理协议
    3.声明代理方法
    4.声明代理属性 
    5.使用代理:
    6.遵守代理协议
    7.设置代理对象
    8.实现代理方法 
    代码实现:下面我们直接上代码,实现点击代理按钮,上面的label显示“代理传的值”*/
    
    //创建代理(传值的页面)
    //.h文件中
    #import <UIKit/UIKit.h>
    //创建代理协议
    @protocol RYTestDelegate <NSObject>
    //声明代理方法
    @optional
    - (void)delegateTestName:(NSString *)name;
    @end
    
    @interface RYDelegateSecondViewController : UIViewController
    声明代理属性
    @property (nonatomic, weak) id<RYTestDelegate> delegate;
    @end
    
    
    //.m文件中
    -(void)clickedDeleBtn{
        NSLog(@"代理");
        //要传递的对象
        NSString *myText = @"代理传的值";
        if ([self.delegate respondsToSelector:@selector(delegateTestName:)]) {
            [self.delegate delegateTestName:myText];
        }
    }
    ————————————————
    
    //2.使用代理(接收值的页面)
    #import "RYDelegateSecondViewController.h"   //创建了代理的页面
    
    @interface RYDelegateViewController ()<RYTestDelegate>
    @property(nonatomic ,strong) UILabel *textLabel;
    @end
    
    
    -(void)clickedNextBtn{
        RYDelegateSecondViewController *vc = [[RYDelegateSecondViewController alloc]init];
         vc.delegate = self;
        [self.navigationController pushViewController:vc animated:YES];
    }
    
    
    -(void)delegateTestName:(NSString *)name{
        self.textLabel.text = name;
        NSLog(@"传值回来====>>代理");
    }
    ————————————————
    
    
    2. 观察者模式(通知机制,KVO机制)

    观察者模式本质上是一种发布-订阅模型,用以消除具有不同行为的对象之间的耦合,通过这一模式,不同对象可以协同工作,同时它们也可以被复用于其他地方Observer从Subject订阅通知,ConcreteObserver实现重现ObServer并将其重载其update方法。

    • 2.1应用场景
      一般为model层对,controller和view进行的通知方式,不关心谁去接收,只负责发布信息。
    • 2.2优势
      解耦合
    • 2.3敏捷原则
      接口隔离原则,开放-封闭原则
    • 2.4实例
      Notification通知中心,注册通知中心,任何位置可以发送消息,注册观察者的对象可以接收。
    /*实现
    说明:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 简而言之,就是A和B,A对B的变化感兴趣,就注册A为观察者,当B发生变化时通知A,告知B发生了变化。这个也叫做经典观察者模式。*/
    ————————————————
    //1.通知机制
    //注册通知接收者的代码(A):
      //注册通知
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(registerCompletion:)
                                                     name:@"RegisterCompeletionNotification"
                                                   object:nil];
        
    -(void)registerCompletion:(NSNotification *)notification{
        NSDictionary *theData = notification.userInfo;
        NSString *username = [theData objectForKey:@"username"];
        NSLog(@"username = %@",username);
    }
    ————————————————
    //投送通知的代码
    -(void)clickedNotifitionCenterBtn{
        NSLog(@"通知");
        
        NSDictionary *dataDic = [NSDictionary dictionaryWithObject:@"通知值" forKey:@"username"];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"RegisterCompeletionNotification"
                                                            object:nil
                                                          userInfo:dataDic];
    }
    ————————————————
    /*问题1. object是干嘛的?是不是可以用来传值?
    答:object是用来过滤Notification的,只接收指定的sender所发的Notification…传值请用userInfo,而不是object
    问题2. iOS中,广播通知(broadcast notification)/本地通知(local notification)/推送通知(push notification)有什么区别和不同?
    出了名字相似以外,广播通知和其他两个通知是完全不一样的: 广播通知是cocoatouch中观察者模式的一种机制, 实现应用内部多个对象的通信…本地通知和推送通知中的"通知"是一种"提示"…通过警告框,发出声音,振动和在应用图标上显示数组等,在计划时间到达时,本地通知通过本地iOS发出,推送通知由第三方程序发送给苹果远程服务器,再由远程服务器推送给iOS特定应用.
    ————————————————
    */
    
    3.单例模式

    单例模式可以保证App在程序运行中,一个类只有唯一个实例,从而做到节约内存。
    在整个App程序中,这一份资源是共享的。
    提供一个固定的实例创建方法。

    • 3.1应用场景
      确保程序运行期某个类,只有一份实例,用于进行资源共享控制。
    • 3.2优势
      使用简单,延时求值,易于跨模块
    • 3.3敏捷原则
      单一职责原则
    • 3.4实例
      [UIApplication sharedApplication]。
    • 3.5注意事项
      确保使用者只能通过 getInstance方法才能获得,单例类的唯一实例。
      java,C++中使其没有公有构造函数,私有化并覆盖其构造函数。
      object c中,重写allocWithZone方法,保证即使用户用 alloc方法直接创建单例类的实例,返回的也只是此单例类的唯一静态变量。
    //实现
    /*一个单例类,保证一个类仅有一个实例,在整个程序中只有一个实例,并且提供一个类方法供全局调用,在编译时初始化这个类,然后一直保存在内存中,到程序(APP)退出时由系统自动释放这部分内存。
    在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),一般用于工具类。例如:登陆控制器,网络数据请求,音乐播放器等一个工程需要使用多次的控制器或方法。
    如工具类、公共跳转类等经常调用的类,都会采用单例模式。*/
    
    static LoginViewController * _instance = nil;
    +(instancetype)sharedLoginHandle{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
               //    loginVC = [[LoginViewController alloc] init];
                     _instance= [[self alloc] init];
        });
         return _instance;
    }
    ————————————————
    
    4.策略模式

    策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

    • 4.1应用场景
      定义算法族,封装起来,使他们之间可以相互替换。
    • 4.2优势
      使算法的变化独立于使用算法的用户
    • 4.3敏捷原则
      接口隔离原则;
      多用组合,少用继承;
      针对接口编程,而非实现。
    • 4.4实例
      排序算法,NSArray的sortedArrayUsingSelector;经典的鸭子会叫,会飞案例。
    • 4.5注意事项
      1、剥离类中易于变化的行为,通过组合的方式嵌入抽象基类
      2、变化的行为抽象基类为,所有可变变化的父类
      3、用户类的最终实例,通过注入行为实例的方式,设定易变行为
      防止了继承行为方式,导致无关行为污染子类。完成了策略封装和可替换性。
    //实现
    /*策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
    简而言之就是把控制其中的一大串 if...else... 或者 switch()单独抽出来写成一些列的算法文件, 减轻了ViewController的负担同时也简化操作,提高代码维护性。算法可以自由切换,避免使用多重条件判断,扩展性良好。
    如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。*/
    ————————————————
    
    //在UITextField的子类CustomField中
    #import <UIKit/UIKit.h>
    #import "InputValidator.h"
    
    @interface CustomField : UITextField
    //抽象的策略
    @property (nonatomic, strong) InputValidator *validator;
    
    /**
     初始化textField
     @param frame frame
     @return 实例对象
     */
    - (instancetype)initWithFrame:(CGRect)frame;
    
    /**
     验证输入合法性
     @return 是否合法,不合法,读取InputValidator当中的errorMessage
     */
    - (BOOL)validate;
    
    @end
    
    //.m
    - (BOOL)validate {
        return [self.validator validateInput:self];
    }
    ————————————————
    
    //创建一个验证策略的基类 InputValidator
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    @interface InputValidator : NSObject
    /**
     策略的输入
     @param input input
     @return 如果为YES,表示测试通过,如果为NO,表示测试不通过
     */
    - (BOOL)validateInput:(UITextField *)input;
    
    //当validateInput为NO的时候,我们来读取errorMessage
    @property (nonatomic, strong) NSString *errorMessage;
    
    @end
    
    #import "InputValidator.h"
    
    @implementation InputValidator
    
    - (BOOL)validateInput:(UITextField *)input {
        return NO;
    }
    
    @end
    ————————————————
    
    //创建 一个邮箱验证方法类EmailValidator,继承于验证策略的基类(InputValidator)
    //然后重写输入验证的验证方法
    #import "EmailValidator.h"
    
    @implementation EmailValidator
    
    - (BOOL)validateInput:(UITextField *)input {
        if (input.text.length <= 0) {
            self.errorMessage = @"邮箱没有输入";
        }
        else{
           self.errorMessage = nil;
        }
        return self.errorMessage == nil ? YES : NO;
    }
    @end
    ————————————————
    
    //创建 一个手机验证方法类PhoneNumberValidator,继承于验证策略的基类(InputValidator)
    //然后重写输入验证的验证方法
    #import "InputValidator.h"
    
    @interface PhoneNumberValidator : InputValidator
    
    //重载了父类的验证方法
    - (BOOL)validateInput:(UITextField *)input;
    
    @end
    
    #import "PhoneNumberValidator.h"
    
    @implementation PhoneNumberValidator
    
    - (BOOL)validateInput:(UITextField *)input {
        
        if (input.text.length <= 0) {
            self.errorMessage = @"手机号没有输入";
        } else {
            if (input.text.length == 11 ) {
                 self.errorMessage = nil;
            } else {
                 self.errorMessage = @"请输入正确的手机号码";
            }
        }
        return self.errorMessage == nil ? YES : NO;
    }
    
    @end
    ————————————————
    
    //在 ViewController中使用策略
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.emailField             = [[CustomField alloc] initWithFrame:CGRectMake(30, 80, 300, 30)];
        self.emailField.placeholder = @"请输入邮箱";
        self.emailField.delegate    = self;
        self.emailField.validator   = [EmailValidator new];
        [self.view addSubview:self.emailField];
        
        
        self.phoneNumberField             = [[CustomField alloc] initWithFrame:CGRectMake(30, 80 + 40, 300, 30)];
        self.phoneNumberField.placeholder = @"请输入电话号码";
        self.phoneNumberField.delegate    = self;
        self.phoneNumberField.validator   = [PhoneNumberValidator new];
        [self.view addSubview:self.phoneNumberField];
        
    }
        #pragma mark - 文本框代理
    - (void)textFieldDidEndEditing:(UITextField *)textField {
        
        CustomField *customField = (CustomField *)textField;
        
        if ([customField validate] == NO) {
            
            NSLog(@"====================>>>>>>>>>>>>    %@",customField.validator.errorMessage);
        }
    }
    
    //相当于在此ViewController的textFieldDidEndEditing:中写了
    - (void)textFieldDidEndEditing:(UITextField *)textField {
     
     
        if(textField == 邮箱textField){
            if (textField.text.length <= 0) {
                NSLog(@"邮箱没有输入");
            }
            else{
                NSLog(@"");
            }
        }
        else  if(textField == 手机textField){
            if (textField.text.length <= 0) {
                 NSLog(@"手机号没有输入");
            } else {
                if (textField.text.length == 11 ) {
                    NSLog(@"");
                } else {
                     NSLog(@"请输入正确的手机号码") ;
                }
            }
        }
     
    }
    ————————————————
    
    

    https://blog.csdn.net/qq_19678579/article/details/86162604
    https://cloud.tencent.com/developer/article/1781975

    相关文章

      网友评论

        本文标题:iOS中常用的几种设计模式

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