你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 設計模式與代碼重構——ios篇

設計模式與代碼重構——ios篇

編輯:IOS開發綜合

下面我針對編程設計模式和蘋果App開發常用設計模式對設計模式進行簡單介紹,也算是自己設計模式的讀書筆記。

一、編程設計模式

代碼設計遵循以下原則:
a、找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。
b、針對接口編程,而不是針對實現編程。
c、多用組合,少用繼承。
d、別調用我們,我們會調用你。
e、一個類應該只有一個引起變化的原因。

下面就介紹一下常用設計模式和其對應的生活中的模式應用:

1,觀察者模式(Subject、Observer):氣象台、報紙雜志
天氣->各種布告板;報紙雜志->訂閱人、讀者
2,裝飾者模式:星巴克咖啡
3,工廠模式:披薩工廠、紅團印、蓋章
4,抽象工廠模式:披薩店
5,單例模式:巧克力工廠鍋爐
6,命令模式:遙控器開關、訂單
7,適配器模式:插座轉接頭
8,模板方法模式:泡茶、咖啡
9,迭代器和組合模式:餐廳並購煎餅屋,菜單的遍歷
10,狀態模式:糖果機、飲料機
11,代理模式:代表輔助完成某功能
12,復合模式:結合兩個或多個模式,解決一般或重復發生的問題。

由於本篇主要講述ios設計模式,這裡不對編程模式展開敘述,後期會對編程模式寫一篇學習筆記。這裡就簡要介紹一下。

二、蘋果App開發常用設計模式及架構探索


1,設計模式的起源:MVC設計模式


1.1在模型對象中封裝數據和基本行為
1.2使用視圖對象向用戶展示信息
1.3用控制器對象聯系其模型和視圖


2,針對接口編程,而不是針對實現編程


2.1.類和類型的差別:一個對象可以具有多個類型,而不同的類的對象可以有相同的類型
2.2.類型的所有對象,包括其子類的對象,都可以針對接口(協議、抽象類的虛方法)請求作出應答。
2.3.協議@protocol與抽象基類

2.3.1協議並不定義任何實現,而只聲明方法,以確定符合協議的類的行為。

如我們最常用的UITableViewDataSource&&UITableViewDelegate。
@protocol UITableViewDataSource

@required

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

@optional

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;

……

@end


@protocol UITableViewDelegate//協議本身可以遵守其他協議

@optional

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;

- (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

……

@end

 

3,對象組合與類繼承


3.1類繼承是白箱復用,對象組合是黑箱復用
3.2 優先使用組合而不是類繼承

這裡舉一個項目裡“發言”用的組合例子:

有多種發言,1、文字2、圖文+文字3、音頻(視頻)4、帶“@”的發言 5、帶地址的發言 6、帶發送范圍的發言等,這個時候我們很難抽象出一個CELL基類滿足各種“發言”的顯示需求,即便可以,每種發言有自己相應的操作,這樣就會導致耦合度也非常高,這個時候我們就需要用到組合,每個CELL實現自己的代理方法實現對應的操作。如下:

//

//YYHomeRecorderTableViewCell.h

//SuperCrm

//

//Created by bill on 15/7/30.

//Copyright (c) 2015年Yonyouup Information Technology Co., Ltd. All rights reserved.

//

 

#import

#import "YYHomeRecorderRowView.h"

#import "YYBaseViewController.h"

#import "YYHomeBusiDetailViewController.h"

#import "YYCustomAnalysisViewController.h"

#import "YYHomeBusinessViewController.h"

#import "YYHomeModel.h"

#import "WFTextView.h"

#import "WFHudView.h"

 

#pragma mark最有價值的生意

@interface YYHomeRecorderTableViewCell : UITableViewCell

 

@property (nonatomic, strong) UILabel *h_titleLable;

@property (nonatomic, strong) UILabel *h_contentLable;

@property (nonatomic, strong) UIButton *h_arrrowButton;

 

@property (nonatomic, strong) UIImageView *h_imgview;

 

- (void)hanleData:(NSString *)contentStr;

@end

 

#pragma mark具體生意

@protocol YYHomeRecorderSecondTableViewCellDelegate

 

- (void)secondTableIntoNextPage:(YYBaseViewController *)baseVC;

- (void)selectChangeScroll;//刪除選擇框

 

@end

 

@interface YYHomeRecorderSecondTableViewCell : UITableViewCell

@property (nonatomic, assign) id delegate;

@property (nonatomic, strong) NSArray *h_dataArray;

 

- (void)handleData:(NSArray *)opportunitySummary;

@end

 

#pragma mark客戶分類信息

@protocol YYHomeRecorderThirdTableViewCellDelegate

 

- (void)thirdTableIntoNextPage:(YYBaseViewController *)baseVC;

 

@end

 

@interface YYHomeRecorderThirdTableViewCell : UITableViewCell

@property (nonatomic, assign) id delegate;

@property (nonatomic, strong) UIScrollView *h_scrollView;

 

//加載數據

- (void)handleData:(NSArray *)accountSummary;

@end

 

#pragma mark客戶生命周期

@interface YYHomeRecorderThirdOneTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel *h_titleLable;

@property (nonatomic, strong) UIButton *h_arrrowButton;

@end

 

#pragma mark記錄

@interface YYHomeRecorderForthTableViewCell : UITableViewCell

@property (nonatomic, strong) UIImageView *h_leftImg;

@property (nonatomic, strong) UILabel *h_contentLable;

@property (nonatomic, strong) UILabel *h_timeLable;

 

@property (nonatomic, strong) NSMutableArray *h_dataArray;

 

/*

*是側滑出現的右視圖時,h_rightImg出現,h_timeLable隱藏

*

*/

@property (nonatomic, strong) UIButton *h_rightImgButton;

- (void)handelData:(YYDynamicResultListModel *)resultListModel;

@end

 

@interface YYHomeRecorderLeftViewTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel * H_leftLable;

@property (nonatomic, strong) UIButton *h_arrowButton;

@end


4,OC開發常用的其他設計模式

4.1單例:通常用於用戶數據、行為的管理
+ (id)shareUserManager{

//Singletoninstance

staticSCRMUserManager *userManager;

 

//Dispatchingit once.

staticdispatch_once_t onceToken;

 

dispatch_once(&onceToken,^{

//Initializingkeyboard manger.

userManager= [[self alloc] init];

userManager.clientDevice= [[YYClientDeviceModel alloc] init];

userManager.accountInfo= [[AccountInfoModel alloc] init];

});

 

//ReturningkbManager.

returnuserManager;

}

4.2 觀察者:類互相依賴,或一對多,接受響應的情況下使用。NSNotificationCenter && NSNotification同名配對使用,如:

[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_LOGIN_LOGOUT object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];

 

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginOrLogout:)

name:NOTIFICATION_LOGIN_LOGOUT object:nil];


4.3代理:為其他對象提供一種代理以控制對這個對象的訪問。


A’a類實現了b類裡定義的協議,那a類實際上也是b類型的代理。
B’代理和BLOCK的選擇(詳見:http://www.cocoachina.com/ios/20150927/13525.html)

a如果對象有超過一個以上不同的事件源,使用delegation。
b如果一個對象是單例,不要使用delegation”

c如果對象的請求帶有附加信息,更應該使用delegation

d如果你使用block去請求一個可能失敗的請求,你應當只使用一個block。如下:

[fetchermakeRequest:^(idresult){

//dosomethingwithresult

}error:^(NSError*err){

//Dosomethingwitherror

}];

 

三、設計模式與代碼重構

設計模式是封裝、繼承、與多態,是編寫代碼之前需要考慮的問題。在編寫代碼過程中,特別是明捷開發的過程中會有很多重復代碼出現,既增加了代碼導致可讀性減弱,再需求變更時往往由於編寫過程中代碼沒有注釋,越來越多的代碼在一個方法裡堆疊,導致最終只有編寫代碼的人才能讀懂代碼,並進行修改。


1,方法傳參

只有參數(特別是參數為類對象時)是變動的時候,才需傳參,否則便可放入方法裡,在調用時減少獲取參數進行傳遞。如:

UIBarButtonItem *item = [self.navigationItem.rightBarButtonItems objectAtIndex:0];

UIButton *buttonItem = item.customView;

[self rightViewHidden:buttonItem];

- (void)rightViewHidden:(UIButton *)sender {

}

 

這裡該這麼寫,

 

[self rightViewHidden]

 

- (void)rightViewHidden {

UIBarButtonItem *item = [self.navigationItem.rightBarButtonItems objectAtIndex:0];

UIButton*buttonItem = item.customView;

}

2,數據、視圖初始化

當控制器由一個controller 推到另一個controller的時,如果數據源來至網絡,那麼應該在viewDidLoad裡對數據、視圖進行初始化,這樣即便網絡請求出問題,視圖也會有默認的顯示,不至於顯示空白,如下:
- (void)viewDidLoad {

[superviewDidLoad];

 

[selfinitData];

[selfinitView];

}

 

 

3,減少沒有意義的參數,如正整形數據類型TAG等,定義有意義的名稱進行代替,如:
typedef NS_ENUM(NSUInteger, HeaderViewTag) {

HeaderViewTagBackImage= 400,// 背景圖

HeaderViewTagImportantImage,//重要生意圖標

HeaderViewTagBussinessName,// 生意名稱

HeaderViewTagBussinessAmount,//生意金額

HeaderViewTagBussinessAvatar,//客戶頭像

HeaderViewTagBussinessCustomer,//客戶名稱

HeaderViewTagDiscoverTime,// 發現日期

HeaderViewTagEstimateTime//預計成交日期

};

4,簡化中間過程增加公用類可擴展性
如YYTypeChooseViewController的tableView.frame計算:

 

- (UITableView *)tableView

{

if (!_tableView) {

_tableView = [[UITableView alloc] init];

if([self needObjNumber]){

if (_objType == YYObjTypeClue) {

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*3)-64, self.view.width, kTypeCellHeight *3);

} else {

if (_isMaster) {

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kTypeCount)-64, self.view.width, kTypeCellHeight *kTypeCount);

}else{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*(kTypeCount-1))-64, self.view.width, kTypeCellHeight *(kTypeCount-1));

}

}

}else if(_objType == YYObjTypeBriefing){

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeRelationCustomer)

{

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*kRelaitonCount), self.view.width, kTypeCellHeight *kRelaitonCount);

}else if(_objType == YYObjTypeBusinessDept || _objType==YYObjTypeLifeForm || _objType == YYObjTypeBusinessStage){

_tableView.frame = CGRectMake(0, -(kTypeCellHeight*kBusinessDeptTypeCount)-64, self.view.width, kTypeCellHeight *kBusinessDeptTypeCount);

}else if (_objType == YYObjTypeAttList || _objType == YYObjTypeAttListTa)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeAttChartAll ||_objType == YYObjTypeAttChartExternal||

_objType == YYObjTypeAttChartInner)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*2)-64, self.view.width, kTypeCellHeight *2);

}

 

_tableView.tableFooterView = [UIView new];

_tableView.delegate = self;

_tableView.dataSource = self;

_tableView.backgroundColor = [UIColor colorWithRed:255.0 green:255.0 blue:255.0 alpha:0.5];

}

return _tableView;

}

 

- (void)viewWillAppear:(BOOL)animated

{

[super viewWillAppear:animated];

self.navigationController.navigationBar.translucent = NO;

 

[UIView animateWithDuration:0.6 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:10 options:UIViewAnimationOptionCurveEaseInOut animations:^{

if([self needObjNumber]){

if (_objType == YYObjTypeClue) {

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*3)-64, self.view.width, kTypeCellHeight *3);

} else {

if (_isMaster) {

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kTypeCount)-64, self.view.width, kTypeCellHeight *kTypeCount);

}else{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*(kTypeCount-1))-64, self.view.width, kTypeCellHeight *(kTypeCount-1));

}

}

}else if(_objType == YYObjTypeBriefing){

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeRelationCustomer)

{

_tableView.frame = CGRectMake(0,- (kTypeCellHeight*kRelaitonCount), self.view.width, kTypeCellHeight *kRelaitonCount);

}else if(_objType == YYObjTypeBusinessDept || _objType==YYObjTypeLifeForm || _objType == YYObjTypeBusinessStage){

_tableView.frame = CGRectMake(0, -(kTypeCellHeight*kBusinessDeptTypeCount)-64, self.view.width, kTypeCellHeight *kBusinessDeptTypeCount);

}else if (_objType == YYObjTypeAttList || _objType == YYObjTypeAttListTa)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*kBriefingTypeCount)-64, self.view.width, kTypeCellHeight *kBriefingTypeCount);

}else if (_objType == YYObjTypeAttChartAll ||_objType == YYObjTypeAttChartExternal||

_objType == YYObjTypeAttChartInner)

{

_tableView.frame = CGRectMake(0, - (kTypeCellHeight*2)-64, self.view.width, kTypeCellHeight *2);

}

} completion:^(BOOL finished) {

 

}];

}

此類起初只有兩三個顯示類型,後來隨著開發的深入,顯示類型越來越多,判斷開始變得越來越復雜。認真查看代碼,此處不過根據各種類型以及各種類型時用友顯示的controller的導航欄是否透明,來計算tableView高度,計算中心點位置,從而使tableView處於正確位置。於是重構為:
//導航欄是否透明

- (BOOL)navBarAlphaIsZero {

return(self.objType == YYObjTypeCustomer || self.objType == YYObjTypeBusiness || self.objType == YYObjTypeContact || self.objType == YYObjTypeBriefing || self.objType == YYObjTypeAttList ||self.objType == YYObjTypeAttListTa);

}

 


- (UITableView *)tableView

{

if(!_tableView) {

_tableView= [[UITableView alloc] init];

CGRectframe = self.view.frame;

[_tableViewsetFrame:CGRectMake(0, -frame.size.height, frame.size.width, frame.size.height)];

_tableView.tableFooterView= [UIView new];

_tableView.delegate= self;

_tableView.dataSource= self;

_tableView.backgroundColor= [UIColor clearColor];

}

return_tableView;

}

 

- (void)viewWillAppear:(BOOL)animated

{

[superviewWillAppear:animated];

self.navigationController.navigationBar.translucent= NO;

 

[UIView animateWithDuration:0.6 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:10

options:UIViewAnimationOptionCurveEaseInOut animations:^{

CGRecttableViewFrame = self.tableView.frame;

if([self navBarAlphaIsZero]){

tableViewFrame.origin.y= 64;

}

else{

tableViewFrame.origin.y= 0;

}

[self.tableViewsetFrame:tableViewFrame];

}completion:^(BOOL finished) {

 

}];

}

這裡簡單舉幾個重構的例子。“設計模式”是在編寫代碼前應該考慮的問題,而“重構”則是在代碼編寫過程中,功能實現完成後,去優化。如果說編程界只有一個真理,那一定是“改變”,我們應該計劃改變,迎接改變,同時挑戰改變增強代碼可讀性,這樣才能不斷提高自己作為一名程序員的職業素養的一件事。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved