01.设计模式之工厂,外观,责任链,消息机制
简单工厂
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
抽象工厂的面向协议编程

抽象工厂有四大角色:
1.抽象产品
2.具体产品(可能多个)
3.抽象工厂
4.具体工厂(可能多个)
上图中已经写明了,每个角色应该做的事情,这边就简单给一个面向协议编程的例子,文后有demo
这里以生产电脑为例:
- 首先创建一个
抽象工厂
和抽象产品
抽象产品
/**
抽象产品--->有产品的一些特征的方法,比如电脑,有显卡,处理器,主板等
*/
#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
- 创建一个三星工厂(具体工厂)
/**
具体的工厂,需要遵守 抽象工厂协议 --->实现协议方法
*/
#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
- 创建一个三星电脑(具体产品)
/**
具体的产品 需要遵守 抽象产品协议,实现协议方法
*/
#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
- 最后是调用
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图:

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