上篇文章講了內存管理,這篇文章主要講解關於架構的一些思考,經過這篇文章你將瞭解到git
- MVC
- MVC變種
- MVP
- MVVM
- 分層設計的優缺點
沒有最好的架構,只有最適合業務的架構。github
蘋果版本的MVC
是Model
和VC
和交互,VC
和View
交互算法
優勢:View
和Model
能夠重複利用,能夠獨立使用數據庫
缺點:Controller
的代碼過於臃腫編程
代碼:設計模式
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData];
}
- (void)loadData{
self.data=[NSMutableArray array];
for (int i = 0; i < 20; i ++) {
FYNews *item=[FYNews new];
item.title =[NSString stringWithFormat:@"title-%d",i];
item.name =[NSString stringWithFormat:@"name-%d",i];
[self.data addObject:item];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.data.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
// Configure the cell...
FYNews *item =[self.data objectAtIndex:indexPath.row];
cell.detailTextLabel.text =item.title;
cell.textLabel.text = item.name;
return cell;
}
//model
@interface FYNews : NSObject
@property (nonatomic,copy) NSString *title;
@property (nonatomic,copy) NSString *name;
@end
複製代碼
這裏是VC
中組裝了tableview
,model
的數據在VC
中在view
中顯示出來,當須要另外的數據的時候,只須要將model
改爲須要的model
而無需更改tableview
的代碼兼容性較好。bash
MVC
變種,其實就是將model
和view
創建了聯繫,view
依據Model
來展現數據,VC
組裝Model
,組裝展現是在view
中實現。網絡
優勢:對Controller進行瘦身,將View的內部細節封裝起來了,外界不知道View內部的具體實現架構
缺點:view依賴於Modelmvc
代碼實現
//.h
@class FYItemModel;
@interface FYAppleView : UIView
@property (nonatomic,strong) FYItemModel *model;
@end
//.m
@interface FYAppleView()
@property (nonatomic,strong) UILabel *nameLabel;
@end
@implementation FYAppleView
-(instancetype)initWithFrame:(CGRect)frame{
if (self =[super initWithFrame:frame]) {
_nameLabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 30)];
[self addSubview:_nameLabel];
}
return self;
}
/*
mvc的變種
*/
- (void)setModel:(FYItemModel *)model{
_model = model;
_nameLabel.textColor = model.bgColor;
_nameLabel.text = model.name;
}
@end
//FYItemModel
@interface FYItemModel : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,strong) UIColor *bgColor;
@end
//ViewController
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadViewOtherMVC];
}
//變種MVC 把View和Model創建起鏈接
//等之後更新view數據只須要 view.model = item;Controllr少了許多代碼
- (void)loadViewOtherMVC{
FYAppleView * view =[[FYAppleView alloc]initWithFrame:CGRectMake(200, 200, 100, 30)];
FYItemModel *item=[[FYItemModel alloc]init];
item.name = @"校長來了";
item.bgColor = [UIColor redColor];
view.model = item;
[self.view addSubview:view];
}
@end
複製代碼
能夠看到model
組裝到view
展現內容是在view
實現的,外部不知道細節,只須要將model
給view
便可,可是隻能傳輸過來model
或者他子類,業務更改的話,須要修改view
的內部model
才能將變動過的數據從新展現出來。
想要監聽view的點擊事件來作一些操做,那麼咱們可使用代理和block
,這裏id
是實現了FYAppleViewProtocol
協議的,weak
修飾防止循環引用,使用協議實現了和VC
的通訊。
@class FYAppleView;
@protocol FYAppleViewProtocol <NSObject>
- (void)FYAppleViewDidClick:(FYAppleView*)view;
@end
@class FYItemModel;
@interface FYAppleView : UIView
@property (nonatomic,strong,readonly) UILabel *nameLabel;
@property (nonatomic,weak) id<FYAppleViewProtocol> delegate;
@property (nonatomic,strong) FYItemModel *model;
@end
複製代碼
稍做更改仍是apple-MVC
// .h
@class FYItemModel;
@interface FYAppleView : UIView
@property (nonatomic,strong,readonly) UILabel *nameLabel;
@end
複製代碼
將View
屬性nameLabel
暴露出來,可是不容許外界進行更改,去掉model
則是MVC
。
MVP
和MVC
很像,只是將VC
換成了Presenter
,vc
和Present
作的事情基本一致,將view
和Model
通訊改到了都和Presenter
通訊。
//MVP
//.h
@interface FYNewsPresenter : NSObject
@property (nonatomic,weak) UIViewController *vc;
//初始化
- (void)setup;
@end
.m
#import "FYNewsPresenter.h"
@interface FYNewsPresenter()<FYAppleViewProtocol>
@end
@implementation FYNewsPresenter
- (void)setup{
FYAppleView * view =[[FYAppleView alloc]initWithFrame:CGRectMake(200, 200, 100, 30)];
FYItemModel *item=[[FYItemModel alloc]init];
item.name = @"校長來了";
item.bgColor = [UIColor redColor];
view.model = item;
[self.vc.view addSubview:view];
}
- (void)FYAppleViewDidClick:(FYAppleView *)view{
NSLog(@"點擊了我");
}
@end
//VC中
@interface ViewController ()
@property (nonatomic,strong) FYNewsPresenter *presenter;
@end
- (void)viewDidLoad {
[super viewDidLoad];
_presenter=[FYNewsPresenter new];
_presenter.vc = self;
[_presenter setup];
}
@end
複製代碼
再次對VC
進行了瘦身,將更多的業務邏輯搬到了FYNewsPresenter
處理,其實所有搬過去,意義比不大,FYNewsPresenter
也會臃腫,也會出現和VC
同樣的困惑。
MVVM
是將FYNewsPresenter
都搬到了FYNewsViewModel
中,而後對FYNewsViewModel
和View
進行了一個雙向綁定,雙向綁定可使用代理,block
或者KVO
實現。
@interface FYNewsViewModel : NSObject
@property (nonatomic,copy) NSString *name;
@property (nonatomic,strong) UIColor *bgColor;
@property (nonatomic,weak) UIViewController *vc;
- (instancetype)initWithController:(UIViewController *)vc;
@end
#import "FYNewsViewModel.h"
@interface FYNewsViewModel()<FYAppleViewProtocol>
@end
@implementation FYNewsViewModel
- (instancetype)initWithController:(UIViewController *)vc{
if (self =[super init]) {
self.vc = vc;
FYAppleView * view =[[FYAppleView alloc]initWithFrame:CGRectMake(100, 200, 100, 50)];
// view.model = item;
view.delegate = self;
view.viewModel = self; //創建kvo
view.backgroundColor = [UIColor lightGrayColor];
[vc.view addSubview:view];
FYItemModel *item=[[FYItemModel alloc]init];
item.name = @"校長來了";
item.bgColor = [UIColor redColor];
self.name = item.name;
self.bgColor = item.bgColor;
}
return self;
}
- (void)FYAppleViewDidClick:(FYAppleView *)view{
NSLog(@"點擊了我");
}
@end
複製代碼
在view
實現
@class FYAppleView,FYNewsViewModel;
@protocol FYAppleViewProtocol <NSObject>
- (void)FYAppleViewDidClick:(FYAppleView*)view;
@end
@class FYItemModel;
@interface FYAppleView : UIView
@property (nonatomic,strong,readonly) UILabel *nameLabel;
@property (nonatomic,weak) id<FYAppleViewProtocol> delegate;
@property (nonatomic,weak) FYNewsViewModel *viewModel;
@property (nonatomic,strong) FYItemModel *model;
@end
@interface FYAppleView()
@property (nonatomic,strong) UILabel *nameLabel;
@end
@implementation FYAppleView
-(instancetype)initWithFrame:(CGRect)frame{
if (self =[super initWithFrame:frame]) {
_nameLabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 30)];
[self addSubview:_nameLabel];
}
return self;
}
/*
mvc的變種
*/
- (void)setModel:(FYItemModel *)model{
_model = model;
_nameLabel.textColor = model.bgColor;
_nameLabel.text = model.name;
}
- (void)setViewModel:(FYNewsViewModel *)viewModel{
_viewModel = viewModel;
[_viewModel addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
//使用FBKVO實現 或者本身使用KVO實現
// __weak typeof(self) waekSelf = self;
// [self.KVOController observe:viewModel keyPath:@"name"
// options:NSKeyValueObservingOptionNew
// block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
// waekSelf.nameLabel.text = change[NSKeyValueChangeNewKey];
// }];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"name"]) {
self.nameLabel.text = change[NSKeyValueChangeNewKey];
}
}
//添加點擊事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if ([self.delegate respondsToSelector:@selector(FYAppleViewDidClick:)]) {
[self.delegate FYAppleViewDidClick:self];
}
}
-(void)dealloc{
[_viewModel removeObserver:self
forKeyPath:@"name"];
}
@end
複製代碼
使用KVO
或者FBKVO
或者RAC
都是能夠的,本章節例子給出了FBKVO
或者本身使用KVO
的實現。
三層架構:
三層架構(3-tier architecture) 一般意義上的三層架構就是將整個業務應用劃分爲:界面層(User Interface layer)、業務邏輯層(Business Logic Layer)、數據訪問層(Data access layer)。區分層次的目的即爲了「高內聚低耦合」的思想。在軟件體系架構設計中,分層式結構是最多見,也是最重要的一種結構。微軟推薦的分層式結構通常分爲三層,從下至上分別爲:數據訪問層、業務邏輯層(又或稱爲領域層)、表示層
目的: 「高內聚,低耦合」的思想
優勢: 下降層與層之間的依賴 標準化
缺點: 系統架構複雜,不適合小型項目
3個層次中,系統主要功能和業務邏輯都在業務邏輯層進行處理。 所謂三層體系結構,是在客戶端與數據庫之間加入了一個
中間層
,也叫組件層。這裏所說的三層體系,不是指物理上的三層,不是簡單地放置三臺機器就是三層體系結構,也不只僅有B/S
應用纔是三層體系結構,三層是指邏輯上的三層,即把這三個層放置到一臺機器上。
三層體系的應用程序將業務規則、數據訪問、合法性校驗等工做放到了中間層進行處理。一般狀況下,客戶端不直接與數據庫進行交互,而是經過
COM/DCOM
通信與中間層創建鏈接,再經由中間層與數據庫進行交互。
三層架構中主要功能與業務邏輯通常要在業務邏輯層進行信息處理和實現,其中三層體系架構中的客戶端和數據庫要預設中間層,成爲組建層。三層架構中的三層具備必定的邏輯性,便是將三層設置到同一個計算機系統中,把業務協議、合法校驗以及數據訪問等程序歸置到中間層進行信息處理,通常客戶端沒法和數據庫進行數據傳輸,主要是利用
COM/DCOM
通信和中間層構建銜接通道,實現中間層與數據庫的數據傳輸,進而實現客戶端與是數據庫的交互
MVC
、MVVM
、MVP
屬於界面層, 當業務複雜,網絡請求和db操做達到了一個新的高度,界面複雜到須要好多人來作,那麼界面、業務、數據須要分層了
分層以後,獲得了一個三層架構或四層架構
數據層也能夠分爲兩層,分爲網絡請求和db層。
具體在工程中咱們一般這樣體現
在vc
中獲取數據
@interface ViewController ()
@property (nonatomic,strong) FYDBPool *db;
@property (nonatomic,strong) FYHttpPool *http;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//當有業務層
[[FYNewsService new] loadNewsWithInfo:nil success:^(NSArray * _Nonnull) {
} fail:^{
}];
//當沒有有業務層
self.db=[FYDBPool new];
self.http=[FYHttpPool new];
[self.db loadNewsWithInfo:@{} success:^(NSArray * _Nonnull ret) {
if ([ret count]) {
NSLog(@"數據獲取成功");
}else{
[self.http loadNewsWithInfo:@{} success:^(NSArray * _Nonnull ret) {
NSLog(@"數據獲取成功");
} fail:^{
NSLog(@"數據獲取失敗");
}];
}
} fail:^{
[self.http loadNewsWithInfo:@{} success:^(NSArray * _Nonnull ret) {
NSLog(@"數據獲取成功");
} fail:^{
NSLog(@"數據獲取失敗");
}];
}];
}
複製代碼
在業務層
@interface FYNewsService ()
@property (nonatomic,strong) FYDBPool *db;
@property (nonatomic,strong) FYHttpPool *http;
@end
@implementation FYNewsService
-(instancetype)init{
if (self = [super init]) {
self.db=[FYDBPool new];
self.http=[FYHttpPool new];
}
return self;
}
- (void)loadNewsWithInfo:(NSDictionary *)info
success:(succcessCallback )succblock
fail:(dispatch_block_t)failBlock{
[self.db loadNewsWithInfo:info success:^(NSArray * _Nonnull ret) {
if ([ret count]) {
succblock(ret);
}else{
[self.http loadNewsWithInfo:info success:^(NSArray * _Nonnull ret) {
succblock(ret);
} fail:failBlock];
}
} fail:^{
[self.http loadNewsWithInfo:info success:^(NSArray * _Nonnull ret) {
succblock(ret);
} fail:failBlock];
}];
}
@end
複製代碼
在db層
typedef void(^succcessCallback)(NSArray *);
@interface FYDBPool : NSObject
- (void)loadNewsWithInfo:(NSDictionary *)info
success:(succcessCallback )succblock
fail:(dispatch_block_t)failBlock;
@end
複製代碼
在網絡請求層
typedef void(^succcessCallback)(NSArray *);
@interface FYHttpPool : NSObject
- (void)loadNewsWithInfo:(NSDictionary *)info
success:(succcessCallback )succblock
fail:(dispatch_block_t)failBlock;
@end
複製代碼
分層目的是瘦身,邏輯清晰,業務清晰,下降耦合,當某一塊足夠複雜時候,均可以進行分層,不侷限於網絡或db
,當db
足夠複雜,也須要進行一個分層來解決複雜調用和處理的問題。 不一樣的人來處理不一樣的分層,相互影響也比較小,下降耦合。
當邏輯層足夠完善,則UI層如何變更都不須要更改邏輯層。
優雅的代碼老是伴隨着各類傳統設計模式的搭配
設計模式(Design Pattern) 是一套被反覆使用、代碼設計經驗的總結 使用設計模式的好處是:可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性 通常與編程語言無關,是一套比較成熟的編程思想
設計模式能夠分爲三大類
建立型模式:對象實例化的模式,用於解耦對象的實例化過程 單例模式、工廠方法模式,等等
結構型模式:把類或對象結合在一塊兒造成一個更大的結構 代理模式、適配器模式、組合模式、裝飾模式,等等
行爲型模式:類或對象之間如何交互,及劃分責任和算法 觀察者模式、命令模式、責任鏈模式,等等
最怕一輩子碌碌無爲,還安慰本身平凡難得。
廣告時間