一、构建者模式
什么是构建者模式?
将一个“复杂对象的构建算法”与它的“部件及组装方式”分离,使得构建算法和组装方式可以独立应对变化;复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。
比如,建造一栋大厦,那么就需要一个总建筑工程师(也就是指导者,相当于uml图中的组装者),N个包工头(也就是承包商,相当于uml图中的构建者),一个包工头有M个小工(也就是搬砖的、贴砖的、木工等等,相当于uml图中的生成者),指导者可以使用承包商A、承包商B、承包商C的自由组合,单个承包商又可以使用搬砖的、贴砖的、木工的自由组合,这样就把构建和组装分离开了。
在创建者模式中,客户端不再负责对象的创建与组装,而是把这个对象创建的责任交给其具体的创建者类,把组装的责任交给组装类,客户端只负责对象的调用,从而明确了各个类的职责。虽然利用创建者模式可以创建出不同类型的产品,但是如果产品之间的差异巨大,则需要编写多个创建者类才能实现,如果这样结合工厂模式更好。
代码示例:
创建构建者协议类Builder
#import <Foundation/Foundation.h>
// 构建者
@protocol Builder <NSObject>
// 构建部分
- (NSString *)builderPart;
@end
创建具体生成者类ConcreteBuild
ConcreteBuild.h
#import <Foundation/Foundation.h>
#import "Builder.h"
@interface ConcreteBuild : NSObject <Builder>
@end
ConcreteBuild.m
#import "ConcreteBuild.h"
@implementation ConcreteBuild
#pragma mark - Builder
- (NSString *)builderPart {
return @"实现协议, 返回产品";
}
@end
创建组装者类Director
Director.h
#import <Foundation/Foundation.h>
#import "Builder.h"
@interface Director : NSObject
// 创建传入的实现者
- (instancetype)initWithBuilder:(id<Builder>)builder;
// 建造
- (NSString *)construct;
@end
Director.m
#import "Director.h"
@interface Director ()
@property (nonatomic, copy) id<Builder> builder;
@end
@implementation Director
- (instancetype)initWithBuilder:(id<Builder>)builder {
self = [super init];
if (self) {
_builder = builder;
}
return self;
}
// 建造
- (NSString *)construct {
// 创建部件
return [self.builder builderPart];
}
@end
ViewController调用
#import "ViewController.h"
#import "Director.h"
#import "ConcreteBuild.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 1.创建生成者, 知道要做的产品
ConcreteBuild *build = [[ConcreteBuild alloc] init];
NSString *str2 = [build builderPart];
// 2.创建承包商
Director *director = [[Director alloc] initWithBuilder:build];
// 3.交付产品
NSString *str = [director construct];
NSLog(@"str = %@, str2 = %@",str, str2);
}
@end
实际开发Demo
生成者(工人)先实现DrawView,好比一开始生成具体小产品,构建者(包工头)再把这些小产品构建成具体大产品DrawBuilder,指导者Director(建筑总工程师)依据自己的需求去选择DrawSubBuilderOne(具体包工头)或者DrawSubBuilderTeo(具体包工头)进行组装。
先创建生成者
DrawView.h
#import <UIKit/UIKit.h>
@interface DrawView : UIView
@property (nonatomic, assign) CGFloat buildLabel;
@property (nonatomic, assign) CGFloat buildButton;
@property (nonatomic, assign) CGFloat buildSizeView;
@end
DrawView.m
#import "DrawView.h"
@implementation DrawView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame: frame];
if (self) {
self.backgroundColor = [UIColor grayColor];
}
return self;
}
// 使用drawRect,可以在控制器中设置值给view.
- (void)drawRect:(CGRect)rect {
[self setBackgroundColor:[UIColor redColor]];
// label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(self.buildLabel, 100, 50, 80)];
label.text = @"TZ";
label.textAlignment = NSTextAlignmentCenter;
label.textColor = [UIColor blackColor];
[self addSubview:label];
// 按钮
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, self.buildButton, 100, 50)];
[btn setTitle:@"蓝色" forState:UIControlStateNormal];
btn.titleLabel.backgroundColor = [UIColor redColor];
btn.titleLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:btn];
// 添加view
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(100, 200, 100, self.buildSizeView)];
subView.backgroundColor = [UIColor blueColor];
[self addSubview:subView];
UIImage *backgroundImage = [UIImage imageNamed:@"tupian"];
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:backgroundImage];
[self addSubview:backgroundView];
}
@end
再创建构建者
DrawBuilder.h
#import <Foundation/Foundation.h>
#import "DrawView.h"
@interface DrawBuilder : NSObject
- (CGFloat)buildLabel; /**< 构建label */
- (CGFloat)buildButton; /**< 构建按钮 */
- (CGFloat)buildSizeView; /**< 构建蓝色的View */
- (DrawView *)loadView; /**< 构建结果 */
@end
DrawBuilder.m
#import "DrawBuilder.h"
@implementation DrawBuilder
- (CGFloat)buildLabel {
return 0;
}
- (CGFloat)buildButton {
return 0;
}
- (CGFloat)buildSizeView {
return 0;
}
- (DrawView *)loadView {
CGFloat drawWidth = 200;
CGFloat drawHeight = 300;
DrawView *drawView = [[DrawView alloc] initWithFrame:CGRectMake(0, 0, drawWidth, drawHeight)];
//
drawView.buildLabel = [self buildLabel];
drawView.buildButton = [self buildButton];
drawView.buildSizeView = [self buildSizeView];
return drawView;
}
@end
具体构建者都继承构建者DrawBuilder
DrawSubBuilderOne.m
#import "DrawSubBuilderOne.h"
@implementation DrawSubBuilderOne
- (CGFloat)buildLabel {
return 1;
}
- (CGFloat)buildButton {
return 1;
}
- (CGFloat)buildSizeView {
return 1;
}
@end
DrawSubBUilderTeo.m
#import "DrawSubBuilderTeo.h"
@implementation DrawSubBuilderTeo
- (CGFloat)buildLabel {
return 10;
}
- (CGFloat)buildButton {
return 150;
}
- (CGFloat)buildSizeView {
return 100;
}
@end
组装者
Director.h
#import <Foundation/Foundation.h>
#import "DrawBuilder.h"
@interface Director : NSObject
+ (DrawView *)creatView:(DrawBuilder *)builder;
@end
Director.m
#import "Director.h"
@implementation Director
+ (DrawView *)creatView:(DrawBuilder *)builder {
DrawView *drawView = [builder loadView];
return drawView;
}
@end
ViewController.m
#import "ViewController.h"
#import "DrawSubBuilderOne.h"
#import "DrawSubBuilderTeo.h"
#import "Director.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)btnClick:(id)sender {
// 创建者
// DrawBuilder *builder = [[DrawSubBuilderOne alloc] init];
DrawBuilder *builder = [[DrawSubBuilderTeo alloc] init];
// 组装
DrawView *drawView = [Director creatView:builder];
drawView.center = self.view.center;
[self.view addSubview:drawView];
}
@end
运行结果:
二、中介者模式
何为中介者模式?
中介者模式是用一个对象来封装一组或者一系列对象的交互方式,使对象间的交互可以在一个中介者对象中处理,从而使各对象耦合松散,而且可以独立的改变它们之间的交互。中介者就好比站在十字路口的交通警察,如果改变十字路口的交通模式,只需要把新的交通策略给交通警察即可,而不是路上的所有车辆,这样才能更好的协调来自不同方向车辆。
中介者模式有什么用?
说到中介者模式的作用,其实从上述的定义中便可以知道其大体用处,无非是用来集中的管理一组对象的交互,从而降低各个对象间的耦合度。当一组对象彼此间的依赖程度较高,导致难以复用时,便可以采用该模式。大家对中介这种角色估计也不陌生,所以今天的设计模式就以这个房地产中介作为故事背景吧!
从无中介.jpg可以看出,要是没有中介的存在,买卖家之间的交流是如此困难且复杂。买家买房要跑去找卖家,卖家买房又得跑去找买家。如果现实真的如此,估计买卖家早就拍桌子说:“老子xx不买(卖)了!”如此反复,房地产业还可能像现在这样撑起国家经济吗?
好了,有中介的接入,一切都变得so easy了!买家要买房,直接到中介看房源,卖家卖房,直接委托中介推销,买卖家通过中介相互取得联系,进行沟通,最后达成买卖共识。呃..不瞎扯了,直接写个demo就清楚了!!!!
如图,同事间通过中介者进行交互,中介者和同事都是抽象类,首先先创建这2个抽象类AbstrctColleague和AbstractMediator。
AbstrctColleague.h
#import <Foundation/Foundation.h>
@class AbstrctColleague;
@protocol ColleagueDelegate <NSObject>
// 跟colleague对象的交互
- (void)colleagueEvent:(AbstrctColleague *)event;
@end
@interface AbstrctColleague : NSObject
@property (nonatomic, weak) id<ColleagueDelegate> delegate;
@end
AbstrctColleague.m
#import "AbstrctColleague.h"
@implementation AbstrctColleague
@end
AbstractMediator.h
#import <Foundation/Foundation.h>
#import "AbstrctColleague.h"
@interface AbstractMediator : NSObject <ColleagueDelegate>
@end
AbstractMediator.m
#import "AbstractMediator.h"
@implementation AbstractMediator
- (void)colleagueEvent:(AbstrctColleague *)event {
}
@end
接着创建具体类Colleague和TypeOneMediator分别继承抽象类AbstrctColleague和AbstractMediator,并实现其方法。
Colleague.h
#import <UIKit/UIKit.h>
#import "AbstrctColleague.h"
@interface Colleague : AbstrctColleague
@property (nonatomic, assign) CGFloat value;
// 修改数值
- (void)changeValue:(CGFloat)value;
@end
Colleague.m
#import "Colleague.h"
@implementation Colleague
- (void)changeValue:(CGFloat)value {
self.value = value;
if (self.delegate && [self.delegate respondsToSelector:@selector(colleagueEvent:)]) {
[self.delegate colleagueEvent:self];
}
}
@end
TypeOneMediator.h
#import "AbstractMediator.h"
#import "Colleague.h"
@interface TypeOneMediator : AbstractMediator
@property (nonatomic, strong) Colleague *colleagueA;
@property (nonatomic, strong) Colleague *colleagueB;
@property (nonatomic, strong) Colleague *colleagueC;
// 查看信息
- (NSDictionary *)values;
@end
TypeOneMediator.m
#import "TypeOneMediator.h"
@implementation TypeOneMediator
// 主要用来查看打印信息.
- (NSDictionary *)values {
return @{@"A":@(self.colleagueA.value),
@"B":@(self.colleagueB.value),
@"C":@(self.colleagueC.value),
};
}
// 指定算法.
- (void)colleagueEvent:(AbstrctColleague *)event {
if ([event isEqual:self.colleagueA]) {
self.colleagueB.value = self.colleagueA.value * 2;
self.colleagueC.value = self.colleagueA.value * 4;
} else if ([event isEqual:self.colleagueB]) {
self.colleagueA.value = self.colleagueB.value / 2.f;
self.colleagueC.value = self.colleagueB.value * 2.f;
} else {
self.colleagueA.value = self.colleagueC.value / 4.f;
self.colleagueB.value = self.colleagueC.value / 2.f;
}
}
@end
最后,创建VC将中介者和多个同事给关联起来,中介者拥有多个同事对象,所有同事的代理对象设置为中介者。
ViewController.m
#import "ViewController.h"
#import "TypeOneMediator.h"
#import "Colleague.h"
@interface ViewController ()
@property (nonatomic, strong) TypeOneMediator *mediator;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mediator = [TypeOneMediator new];
Colleague *colleagueA = [Colleague new];
Colleague *colleagueB = [Colleague new];
Colleague *colleagueC = [Colleague new];
self.mediator.colleagueA = colleagueA;
self.mediator.colleagueB = colleagueB;
self.mediator.colleagueC = colleagueC;
colleagueA.delegate = self.mediator;
colleagueB.delegate = self.mediator;
colleagueC.delegate = self.mediator;
// [colleagueA changeValue:2.f];
// NSLog(@"%@", [self.mediator values]);
[colleagueB changeValue:2.f];
NSLog(@"%@", [self.mediator values]);
}
@end
深层次的应用:
在一些特殊情况下,打开不同的页面(VC)之后,还需要传递一些命令到这个VC,让其做一些特殊的操作,于是可以通过配置URL的参数,再通过参数名和参数值传递给新VC:
[MRRouter openURL:@"scheme://test?aa=11&bb=22"];
更方便的,可以直接用字典来传递参数
[MRRouter openURL:@"scheme://test3" parameters:@{@"ccc":@"333",@"ddd":@"444"}];
于是还需要创建一个映射表,来建立URL和VC之间的映射关系,每增加一个VC,就在这个表里头增加一个对应关系。这里可以利用Objective-C的Runtime来动态地根据类名去映射,简化我们的日常编码操作,具体的实现就不在这里详细描述了,有兴趣可以去这里看具体的实现。
还可以定义一个默认的openURL操作:
[MRRouter sharedInstance].defaultExecutingBlock = ^(id object, NSDictionary *parameters) {
[self.navigationController pushViewController:object animated:YES];
};
这样在一般情况下打开一个新的页面,不需要引入任何头文件,也不需要建立映射关系,只需要调用Router的openURL接口。
通过以中介者模式为基础的Router管理页面的额外好处,就是可以简化服务端push需要打开新页面的操作,当有一个新的活动,要打开一个对应的页面,只需要把这个页面的URL通过push发送给客户端,客户端直接传递给Router即可,省略了大量的if/else的逻辑判断。