iOS开发-Day23-OC设计模式&代码块

1、单例模式

  • 实现单例模式有三个条件

    1、类的构造方法是私有的
    2、类提供一个类方法用于产生对象
    3、类中有一个私有的自己对象

  • 那么在OC中如何实现这3点呢:

    1、类的构造方法是私有的
    我们只需要重写allocWithZone方法,让初始化操作只执行一次
    2、类提供一个类方法产生对象
    这个可以直接定义一个类方法
    3、类中有一个私有的自己对象
    我们可以在.m文件中定义一个属性即可

结合这个小例子看一下单例模式的实现

//  Student.h
#import <Foundation/Foundation.h>

@interface Student : NSObject<NSCopying>

@property(strong,nonatomic) NSString *name;

/**
 *  单例方法
 *
 *  @return 对象类型
 */
+(instancetype)getInstance;
@end

//  Student.m
#import "Student.h"
@implementation Student
//定义静态全局变量
static Student *stu=nil;

+(instancetype)getInstance
{
//    判断对象是否为空
    //    if (stu==nil) {
    //        stu=[[Student alloc] init];
    //    }
    //    return stu;

    /*
     @synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。 一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用。*/
    @synchronized(self) {
        if (stu==nil) {
            stu=[[[self class] alloc] init];
        }
    }
    return stu;
}
/**
 *  防止通过 alloc 或 new  重新创建对象
 *
 *  @param zone 空间  地址
 *
 *  @return 对象
 */
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    if (stu==nil) {

        stu=[super allocWithZone:zone];
    }
    return stu;
}
/**
 *  防止通过copy 复制产生新的对象
 *
 *  @param zone 地址
 *
 *  @return 当前的实例对象
 */
- (id)copyWithZone:(NSZone *)zone
{
    return self;
}
@end

//main.m
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu1=[[Student alloc] init];
        Student *stu2=[Student new];
        NSLog(@"%@",stu1);
        NSLog(@"%@",stu2);

        Student *stu3=[Student getInstance];
        Student *stu4=[Student getInstance];
        stu3.name=@"lisi";
        stu4.name=@"wangwu";
        NSLog(@"%@",stu3);
        NSLog(@"%@",stu4);
        NSLog(@"%@",stu3.name);
        NSLog(@"%@",stu4.name);

        Student *stu5=[stu4 copy];
        NSLog(@"%@",stu5);

    }
    return 0;
}

/*
日志:
<Student: 0x100206a40>
<Student: 0x100206a40>
<Student: 0x100206a40>
<Student: 0x100206a40>
wangwu
wangwu
<Student: 0x100206a40>
*/

2、委托模式(代理模式)

  • 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法给普通用户,特别方法给管理员用户?以上两种需求都非常类似,并且都需要解决一个更大的问题:你如何提供一致的接口给某个对象让它可以改变其内部功能,或者是从来不存在的功能? 可以通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。即代理对象。它可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

  • 经典例子就是网络代理,你想访问facebook或者twitter ,如何绕过GFW,找个代理网站。

  • 再具体一点,就是: A完成一件事,但是自己不能完成,于是他找个代理人B 替他完成这个事情,他们之间便有个协议 (protocol),B继承该协议来完成A代理给他的事情。

来看一个简单的例子:
关于代理租房:

//首先我们定义一个中介协议,要求帮助租房的中介要满足这一协议
//  ZhongJIeDelegate.h
#import <Foundation/Foundation.h>
@protocol ZhongJIeDelegate <NSObject>
-(void)ZuFangZi;
-(void)MaiFangZi;
-(void)GuoHu;
@end
//新建一个HomeLink中介类,要求其遵守中介协议
//  HomeLink.h
#import <Foundation/Foundation.h>
#import "ZhongJIeDelegate.h"
@interface HomeLink : NSObject<ZhongJIeDelegate>
@end
//实现这一个类
//  HomeLink.m
#import "HomeLink.h"
@implementation HomeLink
-(void)ZuFangZi
{
    NSLog(@"我是链家地产的中介,我会帮您租房子!!");
}
-(void)MaiFangZi
{
    NSLog(@"我是链家地产的中介,我会帮您卖房子!!");
}
-(void)GuoHu
{
    NSLog(@"我是链家地产的中介,我帮助您免费过户!!");
}
@end
//新建租客类
//  Customer.h
#import <Foundation/Foundation.h>
#import "ZhongJIeDelegate.h"
@interface Customer : NSObject
//声明一个代理属性,要求其遵循中介协议
@property(assign,nonatomic) id<ZhongJIeDelegate> delegate;
//声明一个zufang方法
-(void)ZuFangZi;
@end

//  Customer.m
#import "Customer.h"
@implementation Customer
-(void)ZuFangZi
{
    NSLog(@"我要租房!!");
    //调用其代理中得zufangZi方法,实现代理租房
    [self.delegate ZuFangZi];
}
@end

//测试
//  main.m
#import <Foundation/Foundation.h>
#import "Customer.h"
#import "HomeLink.h"
#import "WiWj.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //new一个顾客对象
        Customer *customer=[Customer new];
       // new一个HomeLink中介对象
        HomeLink *hl=[HomeLink new];
        //将hl对象赋给顾客的代理属性
        customer.delegate=hl;
        //顾客调用其zufangzi方法,代理租房
        [customer ZuFangZi];
    }
    return 0;
}

3、简单工厂模式

  • 简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

    简单工厂需要用到继承,感觉类似于多态

来一个例子说明一下:

//这里例子是一个简单计算器,按照计算方法生成相应的计算类
//先定义一个父类cal
#import <Foundation/Foundation.h>

@interface Calc : NSObject
/**
 *  属性  num1  num2 为子类提供方便
 */
@property(assign,nonatomic) int num1;
@property(assign,nonatomic) int num2;
/**
 *  计算结果
 *
 *  @return 结果
 */
-(int) jisuan;
@end

//实现它
#import "Calc.h"

@implementation Calc
-(int)jisuan
{
    return 0;
}
@end

//下面新建一个add的类,其重写计算方法以进行加运算
#import "Calc.h"
@interface Add : Calc
@end
#import "Add.h"

@implementation Add
/**
 *  重写父类的方法
 *
 *  @return 加法运算的结果
 */
-(int)jisuan
{
    return self.num1+self.num2;
}
@end

//下面再新建一个Mul的类,其重写计算方法以进行乘法运算
#import "Calc.h"
@interface Mul : Calc
@end
#import "Mul.h"
@implementation Mul
/**
 *  乘法 重写父类的方法
 *
 *  @return 乘法结果
 */
-(int)jisuan
{
    return self.num1*self.num2;
}
@end

//之后我们建立一个工厂,用来判断计算类型并为其返回相应的类
@interface Factory : NSObject
/**
 *  工厂方法
 *  @param oper 运算符号
 *  @return 计算的父类
 */
-(Calc *)fac:(char )oper;
@end

//  Factory.m

#import "Factory.h"

@implementation Factory
-(Calc *)fac:(char )oper
{
    Calc *calc;
     //根据oper的值选择创建类对象
    switch (oper) {
        case '+':
            calc=[Add new];
            break;
        case '*':
            calc=[Mul new];
            break;
        default:
            break;
    }
//    返回的一定是一个子类的对象
    return calc;
}
@end

//测试
#import <Foundation/Foundation.h>
#import "Factory.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        /*
         简单工厂模式
         只关心父类类型 及 传递的参数
         */
         //声明一个工厂对象
        Factory *factory=[Factory new];
        //通过工厂声明一个具有相应操作类型方法的对象
        Calc *calc = [factory fac:'-'];
        //给属性设置值,并调用计算方法
        calc.num1=100;
        calc.num2=200;
        int result =[calc jisuan];
        NSLog(@"result=%d",result);
    }
    return 0;
}

4、工厂模式

  • 什么是工厂模式

        在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。
        工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的策略,很好地符合了开放封闭原则。工厂方法也叫做虚构造器(Virtual Constructor)。
    
  • 什么时候使用工厂方法?

        当是如下情况是,可以使用工厂方法:一个类不知道它所必须创建的对象的类时,一个类希望有它的子类决定所创建的对象时。
    
  • 工厂模式和简单工厂模式的区别

        工厂方法模式和简单工厂模式在结构上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。工厂方法模式可以允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。
        工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么就不妨把抽象工厂类合并到具体的工厂类中去。由于反正只有一个具体工厂类,所以不妨将工厂方法改成为静态方法,这时候就得到了简单工厂模式
    

工厂方法的类结构图:
工厂方法的类结构图

下面来看一个计算器的工厂模式设计

//因为示例,所以就只做了加运算和乘运算
//首先,新建calc类和factory类
//calc.h
#import <Foundation/Foundation.h>
@interface Calc : NSObject
/**
 *  属性  num1  num2 为子类提供方便
 */
@property(assign,nonatomic) int num1;
@property(assign,nonatomic) int num2;
/**
 *  计算结果
 *
 *  @return 结果
 */
-(int) jisuan;
@end

//calc.m
#import "Calc.h"
@implementation Calc
//实现其计算方法、返回一个0、因为子类中都要重写
-(int)jisuan
{
    return 0;
}
@end

//Factory.h
#import <Foundation/Foundation.h>
#import "Calc.h"
#import "Add.h"
#import "Mul.h"
@interface Factory : NSObject
/**
 *  工厂方法
 *
 *  @param oper 运算符号
 *
 *  @return 计算的父类
 */
-(Calc *)oper;
@end

//Factory.m
#import "Factory.h"
@implementation Factory
//实现其oper方法,返回值为空、因为子类中都需要重写
-(Calc *)oper
{
    return nil;
}
@end

//接下来分别是计算类以及其对应的构造工厂

//Add.h
#import "Calc.h"
@interface Add : Calc
@end

//Add.m
#import "Add.h"
@implementation Add
/**
 *  重写父类的方法
 *
 *  @return 加法运算的结果
 */
-(int)jisuan
{
    return self.num1+self.num2;
}
@end

//AddFactory.h
#import "Factory.h"
@interface AddFactory : Factory
@end

//  AddFactory.m
#import "AddFactory.h"
@implementation AddFactory
/**
 *  声明加法对象
 *
 *  @return 一个具有加法方法的对象
 */
-(Calc *)oper{
    return [[Add alloc]init];
}
@end

//Mul.h
#import "Calc.h"
@interface Mul : Calc
@end

//  Mul.m
#import "Mul.h"
@implementation Mul
/**
 *  乘法 重写父类的方法
 *
 *  @return 乘法结果
 */
-(int)jisuan
{
    return self.num1*self.num2;
}
@end

//  MulFactory.h
#import "Factory.h"
@interface MulFactory : Factory
@end

//  MulFactory.m
#import "MulFactory.h"
@implementation MulFactory
/**
 *  声明一个乘法对象
 *
 *  @return 一个具有乘法方法的对象
 */
-(Calc *)oper{
    return [[Mul alloc]init];
}
@end

//代码应该是比较明了的了,计算方法类和其构造工厂一一对应
//下面是测试
//main.m
        //新建一个加法工厂对象
        Factory *addfac=[AddFactory new];
        //新建一个乘法工厂对象
        Factory *mulfac=[MulFactory new];
        //调用加法工厂对象的oper方法新建一个对象
        Calc *add=[addfac oper];
        //调用乘法工厂对象的oper方法新建一个对象
        Calc *mul=[mulfac oper];
        //分别给新对象的属性赋值
        add.num1=2;
        add.num2=3;
        mul.num1=2;
        mul.num2=3;
        //分别调用其计算方法得到结果并输出
        NSLog(@"加法:%d",[add jisuan]);//5
        NSLog(@"乘法:%d",[mul jisuan]);//6

//工厂模式的例子就到这里,相信应该不难理解

5、代码块

代码块本质上是和其他变量类似。不同的是,代码块存储的数据是一个函数体。使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值。

脱字符(^)是块的语法标记。按照我们熟悉的参数语法规约所定义的返回值以及块的主体(也就是可以执行的代码)。

        //声明
        void (^MyBlock)();
        //实现
        MyBlock=^()
        {
            NSLog(@"我的代码块");
        };
        //调用
        MyBlock();

一个例子:

//声明一个名叫 MyBlock的代码块 ,没有返回值类型,带有两个整形参数
typedef  void (^MyBlock)(int a,int b);

int (^TestBlock)(int a,int b);

int MyFun(int (^)(int ,int));

int main(int argc, const char * argv[]) {
    @autoreleasepool {

       /* MyBlock=^(int a,int b)
        {
            int sum=a+b;
            NSLog(@"sum is %d",sum);
        };

        MyBlock(11,22);
        */
        /*
        __block int num1=100;
        __block int num2=400;

        TestBlock =^(int a,int b)
        {
            return num1 +num2;
        };

       int result = MyFun(TestBlock);
        NSLog(@"%d",result);
         */

//        block  代码块类型的变量

        MyBlock block=^(int a,int b)
        {
            NSLog(@"%d",a+b);
        };
//        调用代码块
        block(111,333);

        NSArray *arr=[NSArray array];
        [arr sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
            return 0;
        }];

-15.8.12

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值