没有明确的定义,属于设计的一方面,没明确的把设计和架构进行区分,它可以小到类与类之间的交互,大到不同模块之间,以及不同业务之间的交互,都可以从架构的层面去理解它。
所有架构和设计模式的目的都是为了解耦合
案例需求:女朋友让男朋友去做饭,完了以后给抱抱
GirlFriend类
.h
#import
@interface GirlFriend : NSObject
+ (instancetype)sharedInstance;
- (void)cookingIsDone;
- (void)begin;
@end
.m
#import "GirlFriend.h"
#import "BoyFriend.h"
@implementation GirlFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)cookingIsDone {
NSLog(@"给个爱的抱抱");
}
- (void)begin {
[[BoyFriend sharedInstance] cooking];
}
@end
BoyFriend类
.h
#import
@interface BoyFriend : NSObject
+ (instancetype)sharedInstance;
- (void)cooking;
@end
.m
#import "BoyFriend.h"
#import "GirlFriend.h"
@implementation BoyFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)cooking {
NSLog(@"baby,欧巴开始做饭了");
[[GirlFriend sharedInstance] cookingIsDone];
}
@end
我们看上面的代码,可以看出,BoyFriend类和GirlFriend类是相互依赖的,那我们怎么解决这种依赖关系呢?三种方式代理和block以及通知
BoyFriend.h
#import
@protocol BoyFriendDelegate <NSObject>
- (void)boyFriendMakeCooking;
@end
@interface BoyFriend : NSObject
+ (instancetype)sharedInstance;
- (void)cooking;
@property (nonatomic, weak) id delegate;
@end
BoyFriend.m
#import "BoyFriend.h"
//#import "GirlFriend.h"
@implementation BoyFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)cooking {
NSLog(@"baby,欧巴开始做饭了");
// [[GirlFriend sharedInstance] cookingIsDone];
if (_delegate) {
[_delegate boyFriendMakeCooking];
}
}
@end
GirlFriend.h
#import
#import "BoyFriend.h"
@interface GirlFriend : NSObject <BoyFriendDelegate>
+ (instancetype)sharedInstance;
- (void)cookingIsDone;
- (void)begin;
@end
GirlFriend.m
#import "GirlFriend.h"
@implementation GirlFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)cookingIsDone {
NSLog(@"给个爱的抱抱");
}
- (void)begin {
[BoyFriend sharedInstance].delegate = self;
[[BoyFriend sharedInstance] cooking];
}
- (void)boyFriendMakeCooking {
NSLog(@"给个爱的抱抱");
}
@end
BoyFriend.h
#import
@interface BoyFriend : NSObject
+ (instancetype)sharedInstance;
//- (void)cooking;
@property (nonatomic, copy) void(^myBolock)(NSString *);
- (void)cooking:(void(^)())success;
@end
BoyFriend.m
#import "BoyFriend.h"
//#import "GirlFriend.h"
@implementation BoyFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
//- (void)cooking {
// NSLog(@"baby,欧巴开始做饭了");
//// [[GirlFriend sharedInstance] cookingIsDone];
//
//// if (_delegate) {
//// [_delegate boyFriendMakeCooking];
//// }
//}
- (void)cooking:(void (^)())success {
// // 判断是否有这个block
// if (self.myBolock) {
// // 用参数的形式,把这信息,给block里面赋参数,传出去
// self.myBolock(@"baby,欧巴开始做饭了");
// }
NSLog(@"baby,欧巴开始做饭了");
// 调用这个block,把myBlock回调回去
success(self.myBolock);
}
@end
GirlFriend.h
#import
#import "BoyFriend.h"
@interface GirlFriend : NSObject
+ (instancetype)sharedInstance;
- (void)cookingIsDone;
- (void)begin;
@end
GirlFriend.m
#import "GirlFriend.h"
@implementation GirlFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)begin {
// // 声明这个block, 其实这一步可以省去的
// [BoyFriend sharedInstance].myBolock = ^(NSString *str) {
// NSLog(@"%@",str);
// };
//
// 调用这个方法,里面对block进行声明
[[BoyFriend sharedInstance] cooking:^{
NSLog(@"给个爱的抱抱");
}];
}
@end
block和代理是类似的方式,但是我们发现GirlFriend类中仍然需要引入BoyFriend的头文件,有没有办法,完全解除两个类的关系呢?苹果后期给出的通知就可以解决我们的问题。
Header.h
#ifndef Header_h
#define Header_h
static NSString * const Notif_Begin = @"Notif_Begin";
static NSString * const Notif_cookingIsDone = @"Notif_cookingIsDone";
//#define Notif_Begin @"Notif_Begin"
//#define Notif_cookingIsDone @"Notif_cookingIsDone"
#endif /* Header_h */
GirlFriend.h
#import
#import "Header.h"
@interface GirlFriend : NSObject
+ (instancetype)sharedInstance;
- (void)begin;
@end
GirlFriend.m
#import "GirlFriend.h"
@implementation GirlFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cookingIsDone) name:Notif_cookingIsDone object:nil];
}
return self;
}
- (void)cookingIsDone {
NSLog(@"给个爱的抱抱");
}
- (void)begin {
[[NSNotificationCenter defaultCenter] postNotificationName:Notif_Begin object:nil];
}
@end
BoyFriend.h
#import
#import "Header.h"
@interface BoyFriend : NSObject
+ (instancetype)sharedInstance;
- (void)addNotification;
@end
BoyFriend.m
#import "BoyFriend.h"
@implementation BoyFriend
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)addNotification {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cooking) name:Notif_Begin object:nil];
}
- (void)cooking {
NSLog(@"baby,欧巴开始做饭了");
[[NSNotificationCenter defaultCenter] postNotificationName:Notif_cookingIsDone object:nil];
}
@end
Model View Controller
Model
Paper.h
#import
@interface Paper : NSObject
@property (nonatomic, strong) NSString *content;
@end
View
MVCView.h
#import
#import "Paper.h"
@protocol MVCViewDelegate <NSObject>
- (void)onPrintBtnClick;
@end
@interface MVCView : UIView
- (void)printOnView:(Paper *)paper;
@property (nonatomic, weak) id delegate;
@property (nonatomic, strong) UIButton *btnPrint;
@end
MVCView.m
#import "MVCView.h"
@implementation MVCView
- (void)printOnView:(Paper *)paper {
NSLog(@"在MVCView中打印出的内容:%@",paper.content);
}
- (instancetype)init {
self = [super init];
if (self) {
self.backgroundColor = [UIColor grayColor];
self.btnPrint = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 50)];
[self.btnPrint setTitle:@"print" forState:UIControlStateNormal];
[self.btnPrint addTarget:self action:@selector(onPrintClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.btnPrint];
}
return self;
}
- (void)onPrintClick {
// NSLog(@"采集的事件");
if (_delegate && [self.delegate respondsToSelector:@selector(onPrintBtnClick)]) {
[_delegate onPrintBtnClick];
}
}
@end
Controller
MVCViewController.h
#import
@interface MVCViewController : UIViewController
@end
MVCViewController.m
#import "MVCViewController.h"
#import "MVCView.h"
#import "Paper.h"
@interface MVCViewController () <MVCViewDelegate>
@property (nonatomic, strong) MVCView *myView;
@property (nonatomic, strong) Paper *paper;
@end
@implementation MVCViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.myView = [MVCView new];
self.myView.delegate = self;
self.myView.frame = self.view.bounds;
[self.view addSubview:self.myView];
self.paper = [Paper new];
self.paper.content = @"mvc内容模式";
[self.myView printOnView:self.paper];
}
// 实现了代理方法
- (void)onPrintBtnClick {
int rand = arc4random_uniform(10);
_paper.content = [NSString stringWithFormat:@"改变的数据 %d",rand+1];
[self.myView printOnView:self.paper];
}
@end
MVC架构方式其实就是把数据,视图,控制器三者分离,是最基础的设计模式,MVP和MVVM都是在其基础上衍生出来的。
Controller中的所有逻辑都放在Presenter中实现,与MVC不同的是Model与View是没有任何联系的,都是通过Presenter来交互
代码示例:
注意:MVP的架构方式还是需要Controller的,它只不过是把Controller中的逻辑放在Presenter中去实现
Model
#import
@interface MVPModel : NSObject
@property (nonatomic, strong) NSString *content;
@end
View
MVPView.h
#import
@protocol MVPViewDelegate <NSObject>
- (void)viewShowBtnClick;
@end
@interface MVPView : UIView
@property (nonatomic, weak) id delegate;
- (void)showView:(NSString *)content;
@end
MVPView.m
#import "MVPView.h"
@interface MVPView ()
@property (nonatomic, strong) UILabel *label;
@property (nonatomic, strong) UIButton *btnPrint;
@end
@implementation MVPView
- (instancetype)init
{
self = [super init];
if (self) {
self.backgroundColor = [UIColor grayColor];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, 300, 30)];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.textColor = [UIColor blackColor];
[self addSubview:self.label];
self.btnPrint = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 50)];
[self.btnPrint setTitle:@"来点我呀" forState:UIControlStateNormal];
[self.btnPrint addTarget:self action:@selector(onPrintClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.btnPrint];
}
return self;
}
- (void)showView:(NSString *)content {
self.label.text = content;
}
- (void)onPrintClick {
if (_delegate && [_delegate respondsToSelector:@selector(viewShowBtnClick)]) {
[_delegate viewShowBtnClick];
}
}
创建继承自NSObject的类Presenter
Presenter.h
#import
#import "MVPModel.h"
#import "MVPView.h"
@interface Presenter : NSObject <MVPViewDelegate>
@property (nonatomic, strong) MVPModel *model;
@property (nonatomic, strong) MVPView *view;
- (void)usageLogic;
@end
Presenter.m
#import "Presenter.h"
@implementation Presenter
- (void)usageLogic {
NSString *contentStr = self.model.content;
self.view.delegate = self;
[self.view showView:contentStr];
}
- (void)viewShowBtnClick {
int num = arc4random_uniform(20);
self.model.content = [NSString stringWithFormat:@"mvp--%d-",num];
[_view showView:_model.content];
}
@end
Controller
MVPViewController.m
#import "MVPViewController.h"
#import "Presenter.h"
#import "MVPModel.h"
#import "MVPView.h"
@interface MVPViewController ()
@property (nonatomic, strong) Presenter *presenter;
@property (nonatomic, strong) MVPView *mvpView;
@property (nonatomic, strong) MVPModel *mvpModel;
@end
@implementation MVPViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_presenter = [[Presenter alloc] init];
_mvpView = [[MVPView alloc] init];
_mvpView.frame = self.view.bounds;
[self.view addSubview:_mvpView];
_mvpModel = [MVPModel new];
_mvpModel.content = @"MVP的模式";
// model还没赋值
_presenter.model = _mvpModel;
_presenter.view = _mvpView;
[_presenter usageLogic];
}
@end
MVVMModel.h
#import
@interface MVVMModel : NSObject
@property (nonatomic, copy) NSString *content;
@end
MVVMView.h
#import
#import "MVVMViewModel.h"
@interface MVVMView : UIView
@property (nonatomic, strong) UILabel *labelContent;
@property (nonatomic, strong) UIButton *btnPrint;
@property (nonatomic, strong) MVVMViewModel *vm;
- (void)showView:(MVVMViewModel *)viewModel;
@end
MVVMView.m
#import "MVVMView.h"
@implementation MVVMView
- (instancetype)init
{
self = [super init];
if (self) {
self.backgroundColor = [UIColor grayColor];
self.labelContent = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, 300, 30)];
self.labelContent.textAlignment = NSTextAlignmentCenter;
self.labelContent.textColor = [UIColor blackColor];
[self addSubview:self.labelContent];
self.btnPrint = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 100, 50)];
[self.btnPrint setTitle:@"来点我呀---" forState:UIControlStateNormal];
[self.btnPrint addTarget:self action:@selector(onPrintClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.btnPrint];
}
return self;
}
- (void)onPrintClick {
[self.vm viewModelPrintClick];
}
- (void)showView:(MVVMViewModel *)viewModel {
self.vm = viewModel;
[self.KVOController observe:viewModel keyPath:@"contentStr" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionaryid> * _Nonnull change) {
_labelContent.text = change[NSKeyValueChangeNewKey];
}];
}
@end
MVVMViewModel.h
#import
#import "FBKVOController.h"
#import "NSObject+FBKVOController.h"
#import "MVVMModel.h"
@interface MVVMViewModel : NSObject
@property (nonatomic, copy) NSString *contentStr;
- (void)setWithModel:(MVVMModel *)model;
- (void)viewModelPrintClick;
@end
MVVMViewModel.m
#import "MVVMViewModel.h"
@interface MVVMViewModel ()
@property (nonatomic, strong) MVVMModel *model;
@end
@implementation MVVMViewModel
- (void)setWithModel:(MVVMModel *)model {
self.model = model;
self.contentStr = self.model.content;
}
- (void)viewModelPrintClick {
self.model.content = @"MVVMModel";
int num = arc4random_uniform(20);
self.model.content = [NSString stringWithFormat:@"%d",num];
self.contentStr = self.model.content;
}
@end
MVVMController.m
#import "MVVMController.h"
#import "MVVMModel.h"
#import "MVVMView.h"
#import "MVVMViewModel.h"
@interface MVVMController ()
@property (nonatomic, strong) MVVMView *mvvmView;
@property (nonatomic, strong) MVVMModel *model;
@property (nonatomic, strong) MVVMViewModel *viewModel;
@end
@implementation MVVMController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.model = [[MVVMModel alloc] init];
self.model.content = @"MVVM架构模式";
_viewModel = [MVVMViewModel new];
_mvvmView = [MVVMView new];
_mvvmView.frame = self.view.bounds;
[self.view addSubview:_mvvmView];
[_viewModel setWithModel:_model];
[_mvvmView showView:_viewModel];
}
@end
注意:FBKVOController是个使用KVO的小框架,可以去gitHub上去找。我们在这使用KVO的模式来使ViewModel和View进行数据交互。