美文网首页
01.设计模式之工厂,外观,责任链,消息机制

01.设计模式之工厂,外观,责任链,消息机制

作者: 越来越胖了 | 来源:发表于2020-04-30 13:08 被阅读0次

简单工厂

1.创建一个工厂类,主要 是对共有的一些方法的抽离,同时实现这些方法;子类继承工厂类,可重写这些方法:

#import <Foundation/Foundation.h>
//工厂  --->
@interface Factory : NSObject
- (void)sweet; /**< 甜 */
- (void)poorTaste; /**< 不好吃 */
-(void)testfun;
@end

#import "Factory.h"

@implementation Factory

- (void)sweet{
    NSLog(@"父类--共有的方法,可以父类实现相同的操作,子类可重写--%s",__func__);
}
- (void)poorTaste{
     NSLog(@"父类--共有的方法,可以父类实现相同的操作,子类可重写--%s",__func__);
}

-(void)testfun{
     NSLog(@"父类--共有的方法,可以父类实现相同的操作,子类可重写--%s",__func__);
    
}

@end

2.工厂类下面可能有很多的子类,他们都继承之Factory,拥有父类的方法,同时有他们自己的一些方法;这里创建两个子类:

Apple类:

#import "Factory.h"
@interface Apple : Factory
-(void)appleFunction;
@end

#import "Apple.h"
@implementation Apple
-(void)appleFunction{
    NSLog(@"---%s",__func__);
}
-(void)sweet {
    NSLog(@"重写父类的方法 ---%s",__func__);
}
@end

Oranger类

#import "Factory.h"

@interface Oranger : Factory
-(void)orangerFunction;
@end

#import "Oranger.h"

@implementation Oranger

-(void)orangerFunction{
    NSLog(@"--%s",__func__);
}
@end

3.然后我们需要一个工厂类的实现类:FruitsFactory

#import <Foundation/Foundation.h>
#import "Factory.h"

#import "Apple.h"
#import "Oranger.h"

//工厂的实现--->
typedef NS_ENUM(NSInteger,FruitsType){
    kApple,
    kOrange
};

@interface FruitsFactory : NSObject

+(Factory *)factoryWithType:(FruitsType)type;

@end

#import "FruitsFactory.h"

@implementation FruitsFactory

+(Factory *)factoryWithType:(FruitsType)type{
    Factory *factory = nil;
    // 创建空的对象.在工厂方法里面进行水果的制造
    switch (type) {
        case kApple:
            factory = [[Apple alloc] init];
            break;
        case kOrange:
            factory = [[Oranger alloc] init];
            break;
            
        default:
            break;
    }
    return factory;
}

@end

到这里其实就算完成了,下面的使用了:ViewController类中

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController

@end

#import "ViewController.h"

#import "FruitsFactory.h"
#import "Factory.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Apple *fruits = (Apple *)[FruitsFactory factoryWithType:kApple];
    [fruits sweet];
    [fruits appleFunction];

    Oranger *orange = (Oranger *)[FruitsFactory factoryWithType:kOrange];
    [orange orangerFunction];
    [orange poorTaste];
    
}
@end



这里只是以一个简单的例子进行对工厂类的说明;下面介绍下抽象工厂

抽象工厂

1.创建一个抽象基类:这里创建一个色彩View的基类,只声明,不实现

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

@interface ColorViewFactory : NSObject

+(UIView*)createView;

+(UIButton*)createButton;

@end

#import "ColorViewFactory.h"

@implementation ColorViewFactory

- (instancetype)init
{
   @throw [NSException exceptionWithName:@"抽象基类初始化异常" reason:@"抽象基类,不允许初始化" userInfo:nil];
    
    return nil;
}

@end

2.创建一个工厂的子类:RedCodeViewFactory

#import <Foundation/Foundation.h>
#import "ColorViewFactory.h"
@interface RedCodeViewFactory : ColorViewFactory

@end

#import "RedCodeViewFactory.h"

@implementation RedCodeViewFactory
+(UIView*)createView{
    
    UIView* redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.frame    = CGRectMake(0, 0, 100, 100);
    return redView;
    
}
+(UIButton*)createButton{
    
    UIButton* redBtn = [UIButton  buttonWithType:0];
       redBtn.frame    = CGRectMake(100, 100, 100, 100);
    return redBtn;
}
@end

调用

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

#import "ViewController.h"
#import "ColorViewFactory.h"
#import "RedCodeViewFactory.h"

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    UIView* view = [RedCodeViewFactory createView];
    [self.view addSubview:view];
    
    ColorViewFactory *colorVC = [[ColorViewFactory alloc] init];
    
    NSLog(@"%@",colorVC);
}
@end

OC中也有很多的抽象工厂类,比如NSNumber: NSNumber *intNum = [NSNumber numberWithInt:97];创建的并不是一个NSNumber的实例对象,而是它的一个子类__NSCFNumber,NSNumber *boolNum = [NSNumber numberWithBool:YES];创建的是一个__NSCFBoolean

抽象工厂的面向协议编程

抽象工厂.png

抽象工厂有四大角色:
1.抽象产品
2.具体产品(可能多个)
3.抽象工厂
4.具体工厂(可能多个)
上图中已经写明了,每个角色应该做的事情,这边就简单给一个面向协议编程的例子,文后有demo

这里以生产电脑为例:

  1. 首先创建一个 抽象工厂抽象产品
抽象产品
/**
 抽象产品--->有产品的一些特征的方法,比如电脑,有显卡,处理器,主板等
 */
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@protocol ComputerProtocol <NSObject>

//处理器
-(void)cpu;

//显卡
-(void)displaycard;

//主板
-(void)mainborad;

@end

NS_ASSUME_NONNULL_END

抽象工厂
/**
 抽象工厂 -->具有生成抽象产品的方法
 */
#import <Foundation/Foundation.h>
#import "ComputerProtocol.h"
NS_ASSUME_NONNULL_BEGIN

@protocol ComputerFactoryProtocol <NSObject>

-(id<ComputerProtocol>)productionComputer;

@end

NS_ASSUME_NONNULL_END

  1. 创建一个三星工厂(具体工厂)
/**
 具体的工厂,需要遵守 抽象工厂协议 --->实现协议方法
 */
#import <Foundation/Foundation.h>
#import "ComputerFactoryProtocol.h"
NS_ASSUME_NONNULL_BEGIN

@interface SXComputerFactory : NSObject<ComputerFactoryProtocol>

@end

NS_ASSUME_NONNULL_END
#import "SXComputerFactory.h"
#import "SXComputer.h"

@implementation SXComputerFactory

-(id<ComputerProtocol>)productionComputer{
    
    return [[SXComputer alloc] init];
}

@end

  1. 创建一个三星电脑(具体产品)
/**
 具体的产品 需要遵守 抽象产品协议,实现协议方法
 */
#import <Foundation/Foundation.h>
#import "ComputerProtocol.h"
NS_ASSUME_NONNULL_BEGIN

@interface SXComputer : NSObject<ComputerProtocol>

@end

NS_ASSUME_NONNULL_END
#import "SXComputer.h"

@implementation SXComputer

-(void)cpu{
    NSLog(@"sx_cpu");
}

-(void)displaycard{
    NSLog(@"sx_displaycard");
}
-(void)mainborad{
    NSLog(@"sx_mainborad");
}

@end
  1. 最后是调用
VC中
#import "ViewController.h"
#import "SXComputerFactory.h"
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    id<ComputerFactoryProtocol> factory = [[SXComputerFactory alloc] init];
    id<ComputerProtocol> computer = [factory productionComputer];
    [computer cpu];
    [computer displaycard];
    [computer mainborad];
    
}

以上就是一个完整的电脑生产的面向协议编程的例子,如果有其他电脑要生产,只需要更换掉电脑的生产工厂即可( id<ComputerFactoryProtocol> factory = [[SXComputerFactory alloc] init];中的SXComputerFactory),下面是例子的UML图:

工厂模式-工厂方法.png

外观模式

最经典的例子其实就是买车了;买车人不需要知道具体流程,只要告诉销售是全款或者贷款即可,其他的销售帮你搞定,她会去联系售后,财务,出库等做相应的操作,作为买车人,你啥也不需要干;
创建一个销售类,用户提供是全款还是贷款

#import <Foundation/Foundation.h>

typedef enum{
    payAllMoneyType,
    loansType
    
}buyWayType;


@interface Facade : NSObject

-(void)buyCars:(buyWayType)way;

@end

#import "Facade.h"
#import "SystemOne.h"
#import "SystemTwo.h"
#import "SystemThree.h"

@interface Facade()
@property (strong, nonatomic)SystemOne *one;
@property (strong, nonatomic)SystemTwo *two;
@property (strong, nonatomic)SystemThree *three;

@end

@implementation Facade

#pragma mark - Public

-(void)buyCars:(buyWayType)way{
    
    if(way ==payAllMoneyType){
        [self methodA];
        [self methodB];
    }else if(way == loansType){
        [self methodA];
        [self methodB];
        [self methodC];
    }
  
}

- (void)methodA {
    NSLog(@"\n方法组 A-------------------------");
    [self.one methodOne];
   
}

- (void)methodB {
    NSLog(@"\n方法组 B-------------------------");
    [self.two methodTwo];
   
}

- (void)methodC {
    NSLog(@"\n方法组 C-------------------------");
    [self.three methodThree];
   
}

#pragma mark - Setters & Getters

- (SystemOne *)one {
    if (!_one) {
        _one = [[SystemOne alloc]init];
    }
    return _one;
}

- (SystemTwo *)two {
    if (!_two) {
        _two = [[SystemTwo alloc]init];
    }
    return _two;
}

- (SystemThree *)three {
    if (!_three) {
        _three = [[SystemThree alloc]init];
    }
    return _three;
}

@end

这里具体的操作的类的实现就不写了,下面在VC中调用就可以了

#import "ViewController.h"
#import "Facade.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    Facade* facadeObj = [Facade new];
    [facadeObj buyCars:payAllMoneyType];
}

责任链模式

我给A发送一个请求,A完成不了--->发送给B--->B也执行不了,B发送给C---->就这样一级一级的往下传递,直到请求被处理或者最后无法处理抛出警告或者提示;形成一个责任链去处理事务,俗称踢皮球.

首先创建一个协议:

#import <Foundation/Foundation.h>

@protocol UserProtocol <NSObject>
// 下一个引用
@property (nonatomic, strong) id <UserProtocol> succcessor;

// 处理请求的接口
- (void)handlerRequest:(id)request;

@end

然后我们创建一个管理者,进行指定谁来处理请求:

#import <Foundation/Foundation.h>
#import "UserProtocol.h"

@interface HandlerChain : NSObject <UserProtocol>

@end
#import "HandlerChain.h"

@interface HandlerChain ()

@property (nonatomic, strong) id<UserProtocol> nextSucccessor;

@end

@implementation HandlerChain

- (void)handlerRequest:(id)request {
    [self.nextSucccessor handlerRequest:request];
}

- (void)setSucccessor:(id<UserProtocol>)succcessor {
    self.nextSucccessor = succcessor;
}

- (id<UserProtocol>)succcessor {
    return self.nextSucccessor;
}

@end

这里创建两个可来执行请求的类:

#import <Foundation/Foundation.h>
#import "UserProtocol.h"

@interface PhoneNum : NSObject <UserProtocol>

@end
#import "PhoneNum.h"
#import "RegExCategories.h"

@interface PhoneNum ()
@property (nonatomic, strong) id<UserProtocol> nextSucccessor;
@end

@implementation PhoneNum

- (void)handlerRequest:(id)request {
    NSString *string = request;
    
    BOOL isMatch =[string isMatch:RX(@"^((13[0-9])|(15[^4,\\D])|(18[0,0-9]))\\d{8}$")];
    
    if (isMatch == NO) {
        [self.nextSucccessor handlerRequest:string];
    
    } else {
        NSLog(@"%@ 是电话号码",string);
    }
    
}

- (void)setSucccessor:(id<UserProtocol>)succcessor {
    self.nextSucccessor = succcessor;
}

- (id<UserProtocol>)succcessor {
    return self.nextSucccessor;
}

@end
//这里的判断类,可以不用管,就是对数据判断的一个正则而已

//再来一个类🍺🍺🍺🍺
#import <Foundation/Foundation.h>
#import "UserProtocol.h"

@interface Email : NSObject <UserProtocol>

@end
#import "Email.h"
#import "RegExCategories.h"

@interface Email ()
@property (nonatomic, strong) id<UserProtocol> nextSucccessor;
@end

@implementation Email

- (void)handlerRequest:(id)request {
    NSString *string = request;
    
    BOOL isMatch =[string isMatch:RX(@"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")];
    
    if (isMatch == NO) {
        [self.nextSucccessor handlerRequest:string];
        //如果到这里就没有下级处理了,则可以抛出异常,或者警告了...
    } else {
        NSLog(@"%@ 是邮箱",string);
    }
    
}

- (void)setSucccessor:(id<UserProtocol>)succcessor {
    self.nextSucccessor = succcessor;
}

- (id<UserProtocol>)succcessor {
    return self.nextSucccessor;
}

@end

下面是调用了

- (void)viewDidLoad {
    [super viewDidLoad];
    // 1.创建责任对象
    HandlerChain *handler = [[HandlerChain alloc] init];
    PhoneNum *phoneNum = [[PhoneNum alloc] init];
    Email *email = [[Email alloc] init];
    
    // 2.链接责任链对象
    handler.succcessor = phoneNum;
    phoneNum.succcessor = email;
    
    // 3. 处理请求
    [handler handlerRequest:@"13567867890"];
    
    [handler handlerRequest:@"Tanzhou@sina.cn"];
    
    [handler handlerRequest:@"ZhangSan"];

}

消息机制

主要用到的都是runtime的API,所以不熟悉可以先看下 RunTime

消息发送时,如果sel找不到对应的IMP,则会进入消息的动态方法解析(只解析一次):

类方法未找到时调起,可于此添加类方法实现
+(BOOL)resolveClassMethod:(SEL)sel
实例方法未找到时调起,可于此添加实例方法实现
+(BOOL)resolveInstanceMethod:(SEL)sel

解析失败,会进行消息转发,主要方法:

重定向类方法的消息接收者,返回一个类
-(id)forwardingTargetForSelector:(SEL)aSelector
重定向实例方法的消息接受者,返回一个实例对象
-(id)forwardingTargetForSelector:(SEL)aSelector

具体的实例,可以看这里,主要就是用到上面的两个方法了,传送门
这里对方法调用时的C++代码进行一个简单说明:

Person *person = [Person alloc];
[person init];
[person run];

对应的C++:
Person *person = ((Person *(*)(id,SEL))objc_msgSend)((id)[Person class], @selector(alloc));
person = ((Person *(*)(id,SEL))objc_msgSend)((id)person,@selector(init));
((Person *(*)(id,SEL))objc_msgSend)((id)person,@selector(run));

上面的结构就类似于:func(id,SEL);
这里的(Person ()(id,SEL))objc_msgSend 就是一个func;
后面的就是参数id:(id)[Person class] 和SEL:@selector(alloc)

再来个例子说明下,比如在VC中有一个实例对象obj,obj内部有很多方法如:
-(void)toLeft;
-(void)toRight;等等
我现在希望通过传递一个string,可以动态的调用到obj内部的方法:

-(void)addCommandWithMethodName:(NSString *)methodName{
   
        SEL sel = NSSelectorFromString(methodName);
        [obj performSelector:sel];//这里会有警告
        //这个警告是因为不清楚performSelector执行的方法的返回类型 是void id NSString等导致;解决办法如下:
        ( ( void(*)(id,SEL) )[obj methodForSelector:sel] )(tm,sel);
}

( void(*)(id,SEL)就是一个func名称,[obj methodForSelector:sel] 这个就是一个IMP,就是方法的具体实现指针;后面的(tm,sel),对应消息发送的必传参数(id,SEL)

模拟多继承

这里对于消息机制的使用,还一个就是模拟多继承:

原理:
1.继承NSProxy,然后类的内部提供初始化方法;然后通过获取类OnebaseClass,和TwoBaseClass的方法,把有A方法的 类A 实例对象 保存,把有B方法的 B类 实例对象 保存;
2.当Sub要调用A方法,进行消息重定向,把消息接收者从Sub改成A或者B;Sub想去执行A方法,但是发现自己没有这个方法而OneBaseClass有,发了个指令让OneBaseClass调用A方法(其实还是RunTime那一套);
3.注意:这里有OneBaseClass,TwoBaseClass的实例对象创建;让人感觉好像继承了两个而已,OC是不存在多继承的;

下面的代码就是想让SubClass继承OneBaseClass和TwoBaseClass;

#import <Foundation/Foundation.h>

@protocol OneBaseClassProtocol
- (void)oneBaseClassString:(NSString *)string;
@end
@interface OneBaseClass : NSObject <OneBaseClassProtocol>
@end

#import "OneBaseClass.h"

@implementation OneBaseClass

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSLog(@"-----------%s",__func__);
    }
    return self;
}

- (void)oneBaseClassString:(NSString *)string {
    NSLog(@"oneBaseClassString = %@----%s---%@",string,__func__,self);
    //oneBaseClassString = zhangsan-----[OneBaseClass oneBaseClassString:]---<OneBaseClass: 0x60400001b900>
}

@end

#import <Foundation/Foundation.h>

@protocol TwoBaseClassProtocol
- (void)twoBaseClassString:(NSString *)string;
@end

@interface TwoBaseClass : NSObject <TwoBaseClassProtocol>

@end

#import "TwoBaseClass.h"
@implementation TwoBaseClass
- (void)twoBaseClassString:(NSString *)string {
    NSLog(@"twoBaseClassString = %@",string);
}
@end

下面是SubClass类,他是继承至NSProxy的,NSProxy实现了包括NSObject协议在内基类所需的基础方法,但是作为一个抽象的基类并没有提供初始化的方法。它接收到任何自己没有定义的方法他都会产生一个异常,所以一个实际的子类必须提供一个初始化方法或者创建方法,并且重载forwardInvocation:方法和methodSignatureForSelector:方法来处理自己没有实现的消息。

#import <Foundation/Foundation.h>
#import "OneBaseClass.h"
#import "TwoBaseClass.h"
@interface SubClass : NSProxy <OneBaseClassProtocol,TwoBaseClassProtocol>
+ (instancetype)subClassMethod;
@end

#import "SubClass.h"
#import <objc/runtime.h>

@interface SubClass () {
    NSMutableDictionary *_methodsMap;
}
@end

@implementation SubClass

+ (instancetype)subClassMethod {
    return [[SubClass alloc] init];
}

- (instancetype)init {
    _methodsMap = [NSMutableDictionary dictionary];
    
    // 添加方法  用运行时拿到类里面的方法列表
    [self registerMethodsWithTarget:[OneBaseClass new]];
    [self registerMethodsWithTarget:[TwoBaseClass new]];

    return self;
}

- (void)registerMethodsWithTarget:(id)target {
    unsigned int count = 0;
    // 拿到类里面的方法列表
    Method *methodList = class_copyMethodList([target class], &count);
    
    // 依次拿出来,添加到字典
    for (int i = 0; i < count; ++i) {
        // 方法列表里面的具体方法
        Method method = methodList[i];
        
        SEL sel = method_getName(method);
        [_methodsMap setObject:target forKey:NSStringFromSelector(sel)];
    }
    // delloc 不会提醒
    free(methodList);
//虽然是ARC下,但是ARC并不会管理C的内存,所以需要手动free一下
}

// 通过消息转发, 去实现方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    // 1.方法名
    NSString *methodName = NSStringFromSelector(sel);
    // 2.方法目标对象. 类
    id target = _methodsMap[methodName];
    
    if (target && [target respondsToSelector:sel]) {
        return [target methodSignatureForSelector:sel];
    } else {
        return [super methodSignatureForSelector:sel];
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    // 拿方法
    SEL sel = invocation.selector;
    NSString *methodName = NSStringFromSelector(sel);
    id target = _methodsMap[methodName];
    
    if (target && [target respondsToSelector:sel]) {
        // 执行
        [invocation invokeWithTarget:target];
    } else {
        [super forwardInvocation:invocation];
    }
}

然后就可以VC中调用了:

#import "ViewController.h"
#import "SubClass.h"
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    SubClass *subclass = [SubClass subClassMethod];
    [subclass oneBaseClassString:@"zhangsan"];
    [subclass twoBaseClassString:@"lisi"];
}

@end

如果你对以上设计模式的内容有兴趣,可以给我留言,对其他技术(RN,Flutter,数据结构算法,音视频,OpenGL等)感兴趣也可以留言,一起分享交流,资源共享,共同学习共同进步,在iOS的不归路上越走越远...
抽象工厂-面向协议编程Demo
密码: qrpk

相关文章

网友评论

      本文标题:01.设计模式之工厂,外观,责任链,消息机制

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