前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何优化冗长的条件语句

如何优化冗长的条件语句

作者头像
進无尽
发布于 2018-09-12 08:50:53
发布于 2018-09-12 08:50:53
1.3K00
代码可运行
举报
文章被收录于专栏:進无尽的文章進无尽的文章
运行总次数:0
代码可运行

前言

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我不讨厌简短的 if else,但是对于很长并且负责的 if else 就极其感到不舒服了,代码不但看起来难懂不雅,
关键是维护起来也是一大坨,生怕弄错了之前的逻辑。

OO设计遵循SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转)原则,
使用这个原则去审视if/else,可能会发现很多问题,比如不符合单一原则,
它本身就像一团浆糊,融合了各种作料,黏糊糊的很不干净;
比如不符合开闭原则,每新增一种场景,就需要修改源文件增加一条分支语句,
业务逻辑复杂些若有1000种场景就得有1000个分支流,这种情况下代码不仅仅恶心问题了,效率上也存在很大问题。
由此可见,if/else虽然简单方便,但不恰当的使用会给编码代码带来非常痛苦的体验。
针对这种恶心的if/else分支,我们当然首先想到的去重构它--在不改变代码外部功能特征的前提下对代码内部逻辑进行调整和优化,

而且《重构》一书上有讲到这个问题。if...else, swith...case 是面向过程的代码,在面向对象的代码中应尽可能少地出现。

四个优化方向

【1】尽量少用 else 尽量多用 if reture 的语法方式。 【2】字典的逻辑对应转化作用。 【3】用多态替代条件语句 【4】策略模式,继承重写,抽象父类和统一的接口入口。

一、尽量少用 else 尽量多用 if reture 的语法方式

当一些条件语句难以让人看清他的目的时,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)showName:(NSString *)name
{
    if (name != nil)
    {
        if (name.length > 0)
        {
            NSLog(@"showName");
        }
        else
        {
            NSLog(@"name.length is zero");
        }
    }
    else
    {
        NSLog(@"name is nil");
    }
}

我们可以用卫语句来使得主体逻辑更加清晰尽量不使用 else

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)showName:(NSString *)name
{
    if (name == nil){
        NSLog(@"name is nil");
        return;
    }
    if (name.length == 0){
        NSLog(@"name.length is zero");
        return;
    }
    NSLog(@"showName");
}

二、字典的逻辑对应转化作用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (NSDictionary *)strategyDict{
    if (_strategyDict == nil) {
        _strategyDict = @{
                          @"day1" : [self invocationWithMethod:@selector(playBasketball:)],
                          @"day2" : [self invocationWithMethod:@selector(shopping:)],
                          @"day3" : [self invocationWithMethod:@selector(washClothes:)],
                          @"day4" : [self invocationWithMethod:@selector(playGames:)],
                          @"day5" : [self invocationWithMethod:@selector(sing:)]
             };
    }
    return _strategyDict;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
你会发现字典(哈希表)map是很神奇一种数据结构,再多考虑一步:
1.map的value中保存的不再是基本数据类型,而是对象。
  这样一来,通过不同的key可以拿到不同的对象,如果这些对象的类都实现同一个接口,那么这就是一个加强版的策略模式,
  就是多态性的体现,传统的策略模式传入的是实现类的对象,而通过map加强,只需传入一个数字或字符串即可实现多态。

2.map的value中保存的是函数,通过不同的key(消息类型)可以拿到不同的响应处理函数,则可以实现消息机制或事件驱动。

三、 用多态替代条件语句

使用多态的场景

  • 当对象要根据不同的状态表现不同的行为时。
  • 当你需要在很多地方检查相同的条件时。

我们来看简单的一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Class Update {
    execute() {
        if (FLAG_i18n_ENABLE) {
            //DO A;
        } else {
            //DO B;
        }
    }
    render() {
        if (FLAG_i18n_ENABLE) {
            //render A;
        } else {
            //render B;
        }
    }
}

那么,如何用多态来重写上面的类呢? 我们可以分为两步来操作: - 让 Update 成为抽象类,方法也抽象。 - 在子类中的覆盖方法实现条件语句的分支操作。

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
abstract class Update {
    abstract execute();
    abstract render();
}
class I18NUpdate extends Update {
    execute() {
        //Do A;
    }
    render() {
        //render A;
    }
}
class NonI18NUpdate extends Update {
    execute() {
        //Do B;
    }
    render() {
        //render B;
    }
}

测试方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void testExecuteDoA() {
    Update u = new I18NUpdate();
    u.execute();
    assertX();
}
void testExecuteDoB() {
    Update u = new NonI18NUpdate();
    u.execute();
    assertX();
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
用多态实现的类,通过继承抽象类,重写抽象方法的方式,避免使用了条件语句。
在测试的时候,不需要关心它的状态码,子类本身就已经承载了状态信息。
所以你可以看到,在测试的时候,代码非常的清晰易懂。

使用多态实现的类有两个好处:

  • 我们可以通过增加新的子类来添加新的行为,而且不会影响到原来的代码。
  • 不同的操作和概念在不同的类中,容易理解和阅读。

这个例子太简单,可以看这篇文章中的例子:使用state pattern替代if else,就会发现使用多态替代条件语句不但优雅化了,而且在复杂的情况下是必须要这样处理了。这是一种全新的解决需求扩展和提高项目可维护性的方法。

四、策略模式优化条件语句

策略模式的定义

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
也叫政策模式,定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
策略模式使用的就是面向对象的继承和多态机制,由三个角色构成

1、Rescue封装角色
  也叫上下文角色,起承上启下的封装作用,屏蔽高层模块对策略、算法的直接访问、封装可能存在的变化。
2、Strategy抽象策略角色
  策略、算法家族的抽象,通过为接口,定义每个策略或算法必须具有的方法和属性。
3、ConcreteStrategy具体策略角色
    实现抽象策略中的操作,该类含有具体的算法。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
首先建立一个通用的策略,这里直接命名为Strategy。这个类是最终暴露出来,需要被调用的类。
//Strategy.h
#import <Foundation/Foundation.h>
@interface Strategy : NSObject
- (void) go;
@end

这个类比较简单,只定义了一个go方法。
//Strategy.m
#import "Strategy.h"
@implementation Strategy
- (void)go{
    NSLog(@"I am going outside");
}
@end

接下来定义两个类,分别继承自Strategy类,这两个类中包含了具体的方法实现,是功能的主体部分。

//OldPeopleTravel.h
#import <Foundation/Foundation.h>
#import "Strategy.h"
@interface OldPeopleTravel : Strategy
- (void) go;
@end
.m文件里是具体的针对对老年人的实现方法

//OldPeopleTravel.h
#import "OldPeopleTravel.h"
@implementation OldPeopleTravel

-(void)go{
    [super go];
    NSLog(@"I am old, I need rest");
}

@end

类似的还有YoungPeopleTravel的.h和.m文件

//YoungPeopleTravel.h
#import "Strategy.h"

@interface YoungPeopleTravel : Strategy
- (void) go;
@end

//YoungPeopleTravel.m
#import "YoungPeopleTravel.h"
@implementation YoungPeopleTravel
- (void) go{
    [super go];
    NSLog(@"I am young, I am energetic");
}
@end

以上是策略类和具体的实现类的实现,接下来就是调用这个策略了。

//ViewController.m
#import "ViewController.h"
#import "Strategy.h"
#import "OldPeopleTravel.h"
#import "YoungPeopleTravel.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self goOutside:[[OldPeopleTravel alloc]init]];
    [self goOutside:[[YoungPeopleTravel alloc]init]];
}

- (void)goOutside:(id)theStrategy{
    Strategy *strategy = theStrategy;
    [strategy go];
}

@end
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
可以看到,最终我们调用的是自己的goOutside方法,方法中有一个参数是strategy,
通过传入不同的参数(策略),就可以调用这个策略下具体的方法实现。运行结果表示策略模式已经成功的实现了。
通过调用不同的策略,得到了不同的处理结果。

多态和策略模式之间的联系

我们看完上面的第三中方法(用多态替代条件语句) 和 第四种方法(策略模式优化条件语句)没有感觉两者很相似,其实两者的侧重点不同。

多态性的定义是:同一操作作用于不同的类的实例,将产生不同的执行结果,即不同类的对象收到相同的消息时,得到不同的结果。多态是面向对象程序设计的重要特征之一,是扩展性在“继承”之后的又一重大表现 。对象根据所接受的消息而做出动作,同样的消息被不同的对象接受时可能导致完全不同的行为,这种现象称为多态性。

【1】首先多态是高层次,高度抽象的概念,独立于语言之外,是面向对象思想的精髓,而策略模式只是一种软件设计模式,相对而言更加具体 【2】其次,多态更多强调的是,不同的对象调用同一个方法会得到不同的结果,而策略模式更多强调的是,同一个对象(事实上这个对象本身并不重要)在不同情况下执行不同的方法,而他们的实现方式又是高度类似的,即共享同一个抽象父类并且各自重写父类的方法。 【3】策略模式是通过多态来实现不同子类的选取,是多态调用具体算法的展现。

总结

条件语句的优化,不是上述一种方式可以完成的,往往是上述几种方法的结合使用。

参考文章:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.07.26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
多态重构条件语句
首先,在C#中,多态的体现是什么?虚函数、抽象方法、接口。废话不多说,直接上代码:
Ryan_OVO
2023/10/19
1130
iOS - 关于NSTimer的循环引用
现象 在当前控制器(ViewController)的view上添加了一个自定义的view(LXFTimerView), LXFTimerView在成功创建出来后添加了定时器NSTimer并加入Run
LinXunFeng
2018/06/29
1.1K0
深入浅出 RunLoop(四):RunLoop 与线程
苹果官方文档中,RunLoop的相关介绍写在线程编程指南中,可见RunLoop和线程的关系不一般。Threading Programming Guide(苹果官方文档)
师大小海腾
2020/04/16
1.7K0
iOS iOS与html进行交互
实现的 效果就是上边那样:首先通过webview 进行网络请求 然后进行显示。          然后点击下一页的按钮 通过js的响应显示另一个网页          最后通过下一页的按钮可以返回到首页。     本文仅仅是h5跟ios 的交互的入门 所以没有做细致的描述。 首先先说一下思路:我的项目中是那样的:首先h5从后台拿到数据,然后我请求h5的界面,然后通过h5的按钮进行选择,通过ios控制按钮到那个界面。 这个小demo不涉及数据传输,只是界面的交互。 1 我自己写了两个小网页。 代码如下 首页的
用户1219438
2018/02/01
2.4K0
iOS 如何解决 NSTimer 循环引用
在使用 NSTimer,如果使用不得当特别会引起循环引用,造成内存泄露。所以怎么避免循环引用问题,下面我提出几种解决 NSTimer 的几种循环引用。
网罗开发
2021/04/07
1.5K0
iOS 如何解决 NSTimer 循环引用
系统框架--52:NSTimer会保留其目标对象
计时器要和runloop相关联,runloop会触发任务。创建NSTimer时,可以将其“预先安排”在当前的runloop中,也可以创建好,然后再由开发人员自己调度。无论采用什么方式,只要把计时器放在循环里,它才能创建好触发的任务
xy_ss
2023/11/22
1370
【Java设计模式】019-策略模式 Pro
**策略(Strategy)模式:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。**策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
訾博ZiBo
2025/01/06
680
SpringBoot 中优化 if-else 语句的七种方法实战
大家好,我是默语,擅长全栈开发、运维和人工智能技术。在我的博客中,我主要分享技术教程、Bug解决方案、开发工具指南、前沿科技资讯、产品评测、使用体验、优点推广和横向对比评测等内容。今天,我们将深入探讨如何在 SpringBoot 中优化 if-else 语句。随着代码复杂性的增加,传统的 if-else 语句往往会导致代码难以维护和扩展。本文将介绍七种优化 if-else 语句的实战方法,包括策略模式、枚举与策略模式结合、多态性、Lambda 表达式与函数接口、状态模式、命令模式以及保护子句,帮助你提高代码的可读性和扩展性。💡✨
默 语
2024/11/22
1460
函数响应式编程及ReactiveObjC学习笔记 (二)
之前我们初步认识了RAC的设计思路跟实现方式, 现在我们再来看看如果使用它以及它能帮我们做什么
周希
2019/10/15
5020
iOS KVC和KVO
无论是在我们的今后的工作当中还是面试找工作当中,这两个知识点是十分重要的,有些同学们对这方面的知识还是不是很了解,概念模糊,这里我整理下相关的内容知识分享给大家。
conanma
2021/10/28
8710
Protocol与Delegate 使用方法详解你要知道的KVC、KVO、Delegate、Notification都在这里
你要知道的KVC、KVO、Delegate、Notification都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本系列文章主要通过讲解KVC、KVO、Delegate、Notification的使用方法,来探讨KVO、Delegate、Notification的区别以及相关使用场景,本系列文章将分一下几篇文章进行讲解,读者可按需查阅。 KVC 使用方法详解及底层实现 KVO 正确使用姿势进阶及底层实现 Protocol与Dele
WWWWDotPNG
2018/04/10
1K0
Protocol与Delegate 使用方法详解你要知道的KVC、KVO、Delegate、Notification都在这里
游戏开发设计模式之策略模式
策略模式是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换。这种模式使得算法的变化不会影响到使用算法的客户。
用户11315985
2024/10/16
1830
游戏开发设计模式之策略模式
通知 - NSNotificationCenter
1、每一个应用程序都有一个通知中心(NSNotificationCenter)实例,专门负责协助不同对象之间的消息通信;
tandaxia
2018/09/27
1.1K0
通知 - NSNotificationCenter
iOS常见的内存问题——循环引用
小编在这段儿时间测试过程中发现了好多内存问题,其中较大部分都是由于循环引用造成的内存泄漏,这里小编就借此类问题来给大家分享一下循环引用引发的原因及常见解决方案。
用户5521279
2019/12/10
1.8K0
iOS常见的内存问题——循环引用
策略模式.
    网上介绍设计模式的文章有很多,好文也不少。作为设计模式的初学者,实在不敢多加造次。就仅以此文作为我记忆的备忘录吧!
JMCui
2018/12/07
3660
详解设计模式:策略模式
策略模式(Strategy Pattern)也被称为政策模式(Policy Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。
栗筝i
2022/12/05
1.3K0
详解设计模式:策略模式
SpringBoot中优化if-else语句的七种方法实战
策略模式允许在运行时选择算法的行为。它通过将算法定义成独立的类,并在运行时动态选择使用哪个算法,来避免使用多个if-else或switch语句。
公众号:码到三十五
2024/08/06
940
【OC加强】辛格尔顿和[NSFileManager defaultMagager]以及其他设计模式
我们在工作中使用文件NSFileManager上课时间,创建发现1对象,此2同样的对象地址:
全栈程序员站长
2022/07/05
2470
Objective-C 工厂模式(下) -- 抽象工厂模式
比如用户要买iPhone就创建一个Apple工厂来生产手机, 要买Android手机就创建一个Goolge工厂
周希
2019/10/15
5560
iOS进阶_KVC(&KVC赋值取值过程分析&KVC自定义&异常处理)
在WTPerson.m中我们让accessInstanceVariablesDirectly返回NO,则程序直接崩溃。
编程怪才-凌雨画
2020/09/18
8550
相关推荐
多态重构条件语句
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文