考虑一种情况,你需要调用连续的例程,并在返回一个可以被评估为正值的值时停止(true,object,1,str(1))。
这样做非常诱人:
if (fruit = getOrange())
elseif (fruit = getApple())
elseif (fruit = getMango())
else fruit = new Banana();
return fruit;
我喜欢它,但这不是一个非常经常的风格,可以被认为是专业的生产代码。人们可能更愿意看到更精细的代码,如:
fruit = getOrange();
if(!fruit){
fruit = getApple();
if(!fruit){
fruit = getMango();
if(!fruit){
fruit = new Banana();
}
}
}
return fruit;
根据基本结构的教条,以前的形式是否可以接受?你会推荐吗?
修改
我向那些认为这些职能是工厂或建筑师的人道歉。他们不是,他们只是占位符。问题更多的是语法而不是“工厂化”。这些函数也可以是lambda。
答案 0 :(得分:9)
如果你想要一个简洁的语法,几种语言允许使用“逻辑或”为此目的(C#显式提供了一个合并运算符,因为空值不是假的)。
的Python:
fruit = ( getOrange() or
getApple() or
getMango() or
Banana() )
C#:
fruit = getOrange() ??
getApple() ??
getMango() ??
new Banana();
答案 1 :(得分:4)
我可以想到两种选择。
第一种只允许使用像你这样的语言(PHP?),其中single = in条件就可以了。
if ( (fruit = getOrange()) != null)
elseif ( (fruit = getApple()) != null)
elseif ( (fruit = getMango()) != null)
else fruit = new Banana();
明确表示您正在进行比较,并且单个=不是错误。
fruit = getOrange();
if(!fruit) fruit = getApple();
if(!fruit) fruit = getMango();
if(!fruit) fruit = new Banana();
就像你的第二个例子,但摆脱了丑陋的额外嵌套。
答案 2 :(得分:3)
在强类型语言中,0 / null不等于false,非0 /非null等于true,我会说它可能是安全的,但在一般情况下可读性略低,其中你的方法名称和参数数量可能更大。我个人会避免它,除了某些标准习惯用法,在0 / null等于false和非0 /非null为真的情况下,仅仅因为在阅读代码时可能会混淆赋值与等式检查。弱类型语言中的一些习语,如C语言,如此普遍,以至于避免它们是没有意义的,.e.g,
while ((line = getline()) != null) {
...
}
答案 3 :(得分:1)
正如我所看到的,这个问题不是结构,而是驱动规则。为什么getOrange会出现在getApple等之前?
您可能更有可能看到更多数据驱动的内容:
enum FruitEnum
{
Orange, Apple, Mango, Banana
}
并单独列出
List<FruitEnum> orderedFruit = getOrderedFruit();
int i = 0;
FruitObj selectedFruit;
while(selectedFruit == null && i <= orderedFruit.Count)
{
fruit = FruitFactory.Get(orderedFruit[i++]);
}
if(fruit == null)
{
throw new FruitNotFoundException();
}
也就是说,为了简化代码,您可以使用合并运算符:
fruit = getOrange() ?? getApple() ?? getMango() ?? new Banana();
答案 4 :(得分:1)
在C或C ++中,你可以写:
return (fruit = getOrange()) ? fruit :
(fruit = getApple()) ? fruit :
(fruit = getMango()) ? fruit :
new Banana();
避免这个和你的第一个版本的原因不是“基本结构上的教条”,而是在条件中自行分配令人困惑。一方面,并非所有语言都支持它。对于另一个,它很容易被误读为==
,或者读者可能不确定你是否真正意义,或者可能是==
。为每个条件添加!= 0
变得非常密集和冗长。
GCC有一个允许的扩展名:
return getOrange() ? : getApple() ? : getMango() ? : new Banana();
||
或or
通常可以实现同样的目的(但不能用C或C ++)。
另一种可能性是:
do {
fruit = getOrange();
if (fruit) break;
fruit = getApple();
if (fruit) break;
fruit = getMango();
if (fruit) break;
fruit = new Banana();
} while (false);
使用Perl中的break
可以last
出一个基本块的语言会更好,因为您可以省略do / while(false)
。但可能只有汇编程序员才会喜欢它。
答案 5 :(得分:0)
直接回答你的问题:在条件陈述中出现副作用通常是 坏形式。
作为一种解决方法,您可以将水果构造函数存储在数组中,并找到第一个返回非null(伪代码)的构造函数:
let constructors = [getOrange; getApple; getMango; fun () -> new Banana()]
foreach constructor in constructors
let fruit = constructor()
if fruit != null
return fruit
它像null-coalesce运算符,但更通用。在C#中,您可能会使用linq,如下所示:
var fruit = constructors
.Select(constructor => constructor())
.Filter(x => x != null)
.First();
至少通过这种方式,您可以像工厂类一样传递构造函数,而不是使用null-coalesce运算符对它们进行硬编码。
答案 6 :(得分:0)
我认为没有人提到第一个版本在调试器中可能会有点痛苦。可读性的差异是有争议的,但总的来说,我在条件中避免赋值和函数调用,以便在必要时更容易跟踪执行(即使我从不需要调试它,其他人可能需要稍后修改代码)。