举个例子,在 iOS 开发中,经常会遇到在设置 tableViewCell 时需要根据 indexPath 来设置不同 cell ,一般代码可能会是下面这个样子:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
// 设置第一种 cell
if (indexPath.section == 3 && indexPath.row != 2) {
// cell 代码
return cell;
}
// 设置第二种 cell
if (indexPath.section == 3 && indexPath.row == 2) {
// cell 代码
return cell;
}
// 设置其他 cell
return cell;
}
当然,举的例子比较简单, if...else...也不多,这种场景在开发中很多,一般使用 if...else...或者 switch 时会使代码非常多,求大神们能不能给个思路,遇到这种场景尽量不要出现这种嵌套代码,最好给个实例膜拜膜拜 ^_^
1
wander2008 Jun 30, 2016 via iPhone
不可能
|
2
ourcubk Jun 30, 2016
不可能
|
3
chairuosen Jun 30, 2016
switch 可以打表,简单 if 也可以
|
4
zhuangzhuang1988 Jun 30, 2016 1. 表驱动法(看: 代码大全)
2. 使用 match(看: F#, Scala)' 3. 使用类+继承(看: 设计模式) |
5
Jabin Jun 30, 2016
封装 工厂
|
6
ipconfiger Jun 30, 2016 该用则用, if else 是基础逻辑, 如果不是深层次嵌套的话, 最好不要作一些奇技淫巧出来
|
7
hyyy OP @wander2008
其实我觉得这是一个有趣的话题^_^ |
8
kera0a Jun 30, 2016
|
9
hasbug Jun 30, 2016
这能避免吗? 除非不做判断···
|
10
stcasshern Jun 30, 2016
这个不能吧,印象中这个是最基础得
|
11
ma125125t Jun 30, 2016
目前的 tableView 就是这么艹蛋。但已经有很多开源的方法解决这个问题了(想象一下一百种 cell ,分为数十个 section 和 row 的情况)。去找找吧。
|
12
michaelye1988 Jun 30, 2016 我认为这种情况下用 if else 或者 switch 是非常合理的,至少代码可读性还是在的。如果非要套用一些设计模式什么的,维护起来就痛苦了。
|
13
chmlai Jun 30, 2016
这个简单, 用数据驱动就清晰多了
|
14
spongebobsun Jun 30, 2016
@kera0a 学习了
|
16
chunqiuyiyu Jun 30, 2016
完美消除是不可能的,不然这几个关键字就不会出现。重要的是理清逻辑,不要嵌套过深。
|
17
rekulas Jun 30, 2016
看不懂 两种都是返回 cell 条件为什么不整合在一起
|
18
8bit Jun 30, 2016 via Android
查表,代码大全
|
19
subpo Jun 30, 2016
能只写 if 不写 else 不错了
|
20
harry890829 Jun 30, 2016
这种平级的 if...else...已经不错了,我刚接手了一个代码,到手的时候 4-5 层 if 结构嵌套,全都带 else ,因为需求的关系,我现在又在里面加了两层 if..else...结构,我已经恶心死了
|
21
woshicixide Jun 30, 2016 via Android
多态
|
22
jason19659 Jun 30, 2016
cell = indexPath.section == 3 ? a : indexPath.row == 2 ? b : c
|
23
zhicheng Jun 30, 2016
静态结构这样写没问题,把 3 和 2 消除就行,用 USER_SECTION 常量定义一下。
动态结构用 model 来判断。 |
24
fatedier Jun 30, 2016
简单工厂模式 + 反射,可以实现根据不同的字符串执行不同业务逻辑,但是不适合用这个替换掉所有的 if-else ,不然就是过度设计了。
之前用 c++ 写过一个例子: http://blog.fatedier.com/2015/03/04/decoupling-by-using-reflect-and-simple-factory-pattern-in-cpp/ |
25
lingoerer Jun 30, 2016
1 :[CellViewModel] -> 把每一个 Cell 的 ViewModel 定义出来,放进数组
2 : cellViewModel.identifier, cell.render(cellViewModel) -> 每个 ViewModel 定义自己要用什么 Cell 来展示, dequeue 的时候出不同的 Cell ,然后 Cell 自己对应着绑 UI 3 : tableView 的回调中直接一行同样的代码把 Cell 弄出来 当然,前面还有个: 0 :把你要显示的 Model 的内容 map 成 CellViewModel 的数组 |
26
ibigbug Jun 30, 2016
|
27
muller Jun 30, 2016
策略模式
|
28
davisz Jun 30, 2016
do {
if (false) break; }while(0); |
29
ilotuo Jun 30, 2016
这样?
```java cell = indexPath.section == 3 ? CellFactory.build(...) : indexPath.row == 2 ? CellFactory.build(...): null; ``` |
30
xwartz Jun 30, 2016
map
|
31
mdluo Jun 30, 2016
分支存数组,条件用位运算
|
32
ihuotui Jun 30, 2016 via Android
责任连模式,差不多
|
33
hantsy Jun 30, 2016
State 模式
|
34
twoyuan Jun 30, 2016
首先应该消灭的不是 Magic Number 吗……
|
35
sutra Jun 30, 2016
Map
|
36
youyongsong Jun 30, 2016
pattern match
|
37
0x5e Jun 30, 2016
swift 可能会稍微简化点
let path = (indexPath.section, indexPath.row) switch(path) { case (0, 0): //xxxx case (0, 1): //xxxx } |
38
JasperYanky Jun 30, 2016
model 决定 view controller 层不关心数据 只负责传递
|
39
fhefh Jun 30, 2016
|
40
loveuqian Jun 30, 2016
之前也是这样判断行数,后来改判断模型 title 了
因为判断行数,一不小心,在第 0 行前面加一行,你这所有判断都要重写啊。。 |
41
vincentxue Jun 30, 2016
看来 iOS 迫切需要一个为 UITableView 或者 UICollectionView 解决数据源封装的库。
|
42
sensui7 Jun 30, 2016
OO 中的 tell, don't ask 原则可以消除这种大量的 else , if else 多说明代码抽象的不好, 根据你的逻辑,可以采用相应的设计模式解决
|
43
lalalafq Jun 30, 2016
所有的数据源逻辑(高度,点击,渲染)全部丢到一个 array ;基础的 tableView 委托永远只有大概 10 行左右;
绝壁高聚合,低耦合;产品想怎么改就怎么改;顺序啥的都是小问题。 |
44
JohnSmith Jun 30, 2016
rust 中有个 match
|
45
skyoojaa Jun 30, 2016 via Android
If...else...没法消除,但可以封装判断,让 if...else...里面的代码看起来简洁一些
|
46
realpg PRO 我觉得这种代码很好
瞎搞弄得可维护性差才是大坑 |
47
iyeatse Jun 30, 2016
|
49
so898 Jun 30, 2016
真要很多的话不应该是自定义 Cell ,然后把代码放到 Cell 里面去么?
如果说不能自定义 Cell ,那不是应该通过在外面建立 Cell 内容填充生成的方法来做到精简这一块的代码么? |
50
missdeer Jun 30, 2016
你看,用 OO 设计模式的时候到了,上面说不行的都不是那个年代过来的人
|
51
weirdyu Jun 30, 2016
你这种按照行数来判断返回何种 cell 的方式不太好
|
52
zjyjer Jun 30, 2016
1. 模式匹配
2. 设计一个状态机 每个分支里的代码抽象出一个函数异步调用之 |
53
programgou Jun 30, 2016
我认为我们可以专门提供一个 indexPath 的接口,然后再提供一个 builder ,把实现了 indexPath 接口的类的实例传递给 builder , builder 就可以返回一个 cell 。这样无论你有多少种 indexPath ,只需要维护 builder ,而不会改变 tableView 的任何代码。当你觉得你现在的 builder 过于复杂的时候,你甚至可以为这个 builder 提供接口,这样你可以在不改变原来代码的基础上,替换掉原来的 builder 。总之,类与类建立关系要通过接口,这样就可以在不改变代码的基础上,换掉一个类。也就是换掉一个功能。
这里面涉及到一些设计模式的东西,不过楼主别怕,看不懂书建议去看源码,我博客上写过一个关于建构者模式的分析,你可以参考一下,不过要解决你的问题一个建构者模式肯定是不够的,还有工厂模式。 |
54
sablib Jun 30, 2016
如果是 swift 的话,就用 enum 了。
|
55
billion Jun 30, 2016
如果语言是 Python 的话,可以使用字典解决:
``` def a(para): xxx def b(para): xxx def c(para): xxx functionDict = {'a':a, 'b': b, 'c': c} result = functionDict[name](para) ``` 这样,当你需要使用 switch 或者 if ...else 来调用函数的时候,可以通过: functionDict('a')(para)这种方式调用函数。 |
56
chrisstyle Jun 30, 2016
同 25 楼~
推荐 |
57
i4mszengg Jun 30, 2016
我想应该不用故意写一些奇葩的逻辑,日后维护很痛苦的吧,如果 单个 if 的 condiftions 比较多,可以嵌套 if , 这样更容易懂些,日后好维护。
|
58
jasonlz Jun 30, 2016
用状态机。
|
60
djyde Jun 30, 2016
程序之所以是程序,因为它能 if else
|
61
EAimTY Jun 30, 2016 via Android
不可能的,不论用什么方法代替,底层肯定还会是 if else
|
62
adrianzhang Jun 30, 2016 via Android
结构化语言之前,都用 goto ,汇编里见 jump 更多。
|
63
xwing Jun 30, 2016
命令链模式。
|
64
hrong Jun 30, 2016 via Android
表驱动,策略模式。
有人说什么反射,想想反射里面有多少个 if/else 就知道用反射有多么的得不偿失 |
65
cocoaChina Jun 30, 2016 via Android
这种判断逻辑必须有,但逻辑内实现却可以瘦身,尽量多用 switch
|
66
powergx Jun 30, 2016 via iPhone cpu 晶体管可是只有通河短两种情况, lz 竟然说不用 if
|
67
rashawn Jun 30, 2016
最下面都是一样的吧 不用这个是不是能跑的快一点
|
70
peneazy Jun 30, 2016 via Android
我只知道 js 怎么消除这种东西。利用多态性,比如原型继承,把每一种可能封装在原型里,构造函数直接调用。看看设计模式吧,有至少两种模式能大幅度减少判断语句。
|
71
holy_sin Jun 30, 2016
问题的核心就是区分出不同类型的 cell 要如何渲染。如果在 vc 里做,那么 collectionView 对应的所有 datasource 和 delegate 都需要分别写一套区分方法。所以比较好的方法是在构造数据源的时候,指定好每一种 cell 如何显示。由于 cell 信息可能会比较多,所以就衍生出来用 cellViewModel 来管理这些信息,这就是数据驱动的意思吧。当 cell 的排列关系需要改动的时候,只需要修改构造数据源的地方。其实就是 @lingoerer 所说的做法。
|
72
hinkal Jun 30, 2016
利用多态减少 if else 才是正解,否则说明上下文中 if else 不应该被消除。
|
73
jackisnotspirate Jun 30, 2016 via iPad |
74
tutuge Jul 1, 2016
模板方法解决, cell 基类,传入 index 等参数,让 cell 不同子类自己处理。也就是多态=。=
|
75
yangff Jul 1, 2016 via Android
@zhuangzhuang1988 讲道理 switch 本来就是 jump table ,编译器还会把它塞到 ro 的段上,安全性还更好些
|
77
wangyifei6817 Jul 1, 2016
这里不谢 也要写到别的地方 换个地方恶心而已
|
78
miaotaizi Jul 1, 2016
策略模式?
|
79
wander2008 Jul 1, 2016 via iPhone
@hyyy 是的,逻辑层面确实不行。
搞设计模式可以。 java |
80
wmhx Jul 1, 2016
java 的工厂模式. 参见 jfinal
|
84
bobuick Jul 1, 2016
模式匹配吧, rust 或 haskell 那种模式匹配方式,不过完全杜绝是不可能的, 不过可以大部分解决了
|
85
nozama Jul 1, 2016 via iPhone
这种情况 mvvm 吧, datasource 里面只存放一堆抽象的 cellViewModel ,并通过工厂来获得具体的 cell ,工厂可以用数据来驱动。
|
86
Balthild Jul 1, 2016
全部用 goto
|