代码的坏味道

重构:就是在不改变代码的外在行为的前提下,对代码做出修改,以改进程序的内部结构.

重复代码

// 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中)

数据泥团

基本类型偏执

便于后期使用和扩展,使用对象替换掉某些基本类型,甚至结构类型(结构类型比较耗费性能).

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函数,保护数据不容易在外部被修改.

被拒绝的遗赠

针对于父类和子类之间的关系. 子类继承了父类中子类不需要的部分函数和数据.
解决方案:

过多的注释

理想状态下,应该是代码自解释