代码的坏味道
重构:就是在不改变代码的外在行为的前提下,对代码做出修改,以改进程序的内部结构.
重复代码
-
重复使用的魔法数字,建议定义为常量(eg:cell重用标记,cell默认高度,item默认宽高,推送标识符)
-
重复的代码块:建议作为局部block代码块或者局部方法
比如:首页运营广告位允许跳入帖子详情,和帖子列表中cell点击效果一致.
方法对外需要暴漏统一的参数列表(比如
postID
,postType
),并做出一致的行为. PS:不建议在此方法中改变甚至访问全局变量. -
重复的类实现:使用类的继承或者扩展代替
兄弟子类中含有相同的属性或者方法时,将其单独拉出移到父类中.
含有相似的方法时,可以将差异部分作为参数自定义方法实现.此处也可以利用多态特性实现.
方法的定义时可以根据不同的case,定义不同的方法实现.比如不同的
init
方法.
// Male
@interface Male : People
@property (assign, nonatomic) NSInteger age;
- (void)eat;
- (void)playVideoGame;
@end
// Female
@interface Female : People
@property (assign, nonatomic) NSInteger age;
- (void)eat;
- (void)playVRGame;
@end
Male
类和Female
中都含有eat
方法.
typedef NS_ENUM(NSInteger, GameType) {
GameType_VR,
GameType_Video
};
// People
@interface People : NSObject
@property (assign, nonatomic) NSInteger age;
- (void)eat;
- (void)playGame:(GameType )gameType;
//可以利用多态,判断调用方法的当前实例来实现不同的逻辑
- (void)playGame;
@end
不同的类中含有重复的代码逻辑.如果可以,将重复的代码作为一个新类,在不同的类中使用此类替代重复代码逻辑.
// Male
@class PostInfo;
@interface Male : People
@property (assign, nonatomic) NSInteger age;
@property (strong, nonatomic) NSArray <PostInfo *> *userPostArray;
- (void)eat;
- (void)playVideoGame;
@end
过长的函数(函数瘦身)
- 将大量的参数,临时变量等重复代码移出作为新的函数调用
@weakify(self);
[[[[SearchFundRating4C signal_requestWithkey:searchKey] doNext:^(CallBackModel_SearchFundRating4C* x) {
//转换数据
@strongify(self);
self.tableViewHeaderFooterShown = NO;
//后端返回数据最多为5条(同h5逻辑),不做分页处理(@张成确认)
NSMutableArray *mutableArray = [NSMutableArray new];
for (SearchFundRating4C_FundlistObject *fundListObject in x.fundlistArray) {
FundSearchInfoModel *model = [FundSearchInfoModel new];
model.fundName = fundListObject.fullname;
model.fundCoode = fundListObject.fundcode;
[mutableArray addObject:model];
}
self.dataSourceArray = [mutableArray copy];
}] doError:^(NSError *error) {
@strongify(self);
self.requestError = error;
MSLog(@"请求失败");
}] catchTo:[RACSignal empty]];
- 将类似判断条件/循环语句等可能暴漏多处或经常修改的逻辑部分作为一个函数使用
#pragma mark - format
- (BOOL)formatSearchText:(NSString *)searchText{
//确认4个数字,4个字母的时候出现模糊提示,2个汉字的时候出现模糊提示。
if (searchText && [ToolUtil getLengthMixedString:searchText] >= 4) {
return YES;
}
return NO;
}
过大的类(类瘦身)
- 类中含有大量的属性值,可以将相关的属性提炼作为新类/子类
@interface People : NSObject
@property (assign, nonatomic) NSInteger age;
//联系信息
@property (copy, nonatomic) NSString *TelNumber;
@property (copy, nonatomic) NSString *officeNumber;
- (void)eat;
- (void)playGame:(GameType )gameType;
@end
- 类中含有重复代码,可以提炼为方法
过长的参数列表
将过多的参数合并为一个对象或者结构体作为参数传入方法内部.
//传入CGRect对象,而不是上左宽高
[[HomeFundAllocationView alloc] initWithFrame:CGRectMake(kScreenWidth, 0, kScreenWidth, kScrollViewHight)]
// NSIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
// NSInteger
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
发散式变化
一般指一个类受到多种变化的影响. 针对的是同一个类.
将可能会修改的类中方法单独移出,避免不同的变化糅合在一起都会对类产生影响.S.O.L.I.D
中的单一职责原则.
引入了一种新的数据库,需要修改函数中的某个方法;引入新的支付工具,需要修改函数中的某个方法.
霰(xian
)弹式修改
一般指一种变化引起多个类做出相应的修改. 强调多个类.
将散落在类中或者工程中的各处修改作为函数统一在一处.统一了代码风格,避免过多/过少修改造成的错误.
比如:init请求地址增加时间戳的处理,有时init请求需要请求三个地址,给地址增加时间戳可能会散落在多处.
依恋情节
防止贫血型Model的出现.Model不只是数据存储格式化,还包含数据的操作.
依恋情结现象是:A类中的函数大量引用了B类中的属性/方法,过度依赖B类.
是指Model的某个数据操作放错了位置,需要将数据操作放置到对应的Model中.(关键点:尽可能的将数据和数据的行为操作一起放在对应的Model中)
数据泥团
- 两个类中含有相同的字段:将这些属性提炼到独立类中,或者使用继承多态解决.
- 函数声明中含有相同的参数列表:类似于
4.过长的参数列表
,将相同的参数列表作为对象或结构体作为参数.
基本类型偏执
便于后期使用和扩展,使用对象
替换掉某些基本类型
,甚至结构类型
(结构类型比较耗费性能).
switch惊悚现身
可以使用多态
的特性,将switch语句控制在一处.
平行继承体系
平行继承体系
是6.霰弹式修改
的特殊情况.
为某个类增加一个子类后,必须也为另一个类增加一个子类.(类似于渠道的概念,增加了新渠道后支付方式,对账账单都需要修改)
常见的解决方案是:让某一类的实例引用另一个类实例. 将相同的操作抽象到父类/引用类解决.
冗赘类
精简无用的类.
夸夸其谈未来性
要考虑其可扩展性
- 无用的抽象类
- 无用的函数参数
- 函数名称命名
令人迷惑的暂时字段
临时变量
过度耦合的消息链
消息事件传递链过长
// 判断登陆状态
[[BackgroundViewController share] isUserLogin];
// BackgroundViewController内实现的方法
- (BOOL)isUserLogin {
return [[UserInfo shareInstance] isLoginStatus];
}
中间人
过度使用委托,代码设计过重.
- 去除中间人,使上游直接和真正负责的对象打交道.
- 把中间人变成对象的子类,既可以扩展对象的行为,也不必担心过多是委托.
狎昵关系
类似于依恋情节
两个类的关系过于亲密,可能会互相访问对方属性,双向关联或者继承.
异曲同工的类
实现了同一功能的类
不完美的类库
- 修改类库中的一两个函数
Date newStart = new Date (previousEnd.getYear(),previousEnd.getMonth(),previousEnd.getDay()+1);
Date newStart = nextDay(previousEnd);
private static Date nextDay(Date avg) {
return new Date (avg.getYear(),avg.getMonth(),avg.getDay()+1);
}
- 添加额外的行为
纯稚的数据类
类似于贫血型Model.期望为model增加set/get函数,保护数据不容易在外部被修改.
被拒绝的遗赠
针对于父类和子类之间的关系. 子类继承了父类中子类不需要的部分函数和数据.
解决方案:
- 为子类新建一个兄弟类,将不需要的部分移至此类
- 用委托代替继承关系
过多的注释
理想状态下,应该是代码自解释