Dart中的工厂构造函数返回null是否可以接受



我一直在用Dart编写一些代码。我真的很喜欢工厂的建造师,但我担心我在滥用它的用处。特别是,当我编写一个值对象类时,如果验证失败,有时会返回null。

class EmailAddress {
static final RegExp _regex = new RegExp(...);
final String _value;
factory EmailAddress(String input) {
return _regex.hasMatch(input) ? new EmailAddress._internal(input) : null;
}
const EmailAddress._internal(this._value);
toString() => _value;
}

起初,这似乎并没有那么糟糕。然而,当你实际使用它时,这就是你所看到的。

methodThatCreatesAnEmailAddress() {
var emailAddress = new EmailAddress("definitely not an email address");
...
}

这之所以不好,是因为来自另一种静态类型语言(如Java或C++)的开发人员希望emailAddress始终初始化为非null值。这是完全可以接受的原因是构造函数是工厂的,因此允许返回null值。

那么,这是一种糟糕的做法还是利用了一个有用的功能?

使用空安全Dart,factory构造函数不再允许返回null

迁移时,返回null的现有factory构造函数应替换为static方法。

从工厂返回null值是可以接受的,因为Dart factory软件概念中的内置factory功能没有任何null限制。

另一方面,我可以重新表述你的问题";从相等运算符"返回null可接受吗;

bool operator ==(other) {
return null;
}

这也是可以接受的,因为不存在此运算符不能返回null值的限制。

但还有另一个问题?为什么要这样做以及如何避免?

factory EmailAddress(String input) {
return _regex.hasMatch(input) ? new EmailAddress._internal(input) :
throw "something went wrong";
}

第页。S.

我个人认为,从Dart的factory返回nullbad practice,因为Dart的工厂很难与构造函数区分开来。

从外表上看,它们看起来像构造函数,不同之处在于它们更强大,因为它们可以构造不同类型的对象。

他们也有自己的限制,但这是另一回事。

我不同意其他答案:至少对于命名的factory构造函数,我认为返回null没有任何问题。

factory构造函数和static方法之间的主要区别在于,factory构造函数可以与new一起使用,并且可以是未命名的默认构造函数。现在不鼓励使用new,因此在大多数情况下,命名的factory构造函数与调用站点上的static方法调用是不可区分的。

我看不出static方法返回null有任何问题,因此,我也看不出命名的factory构造函数返回null有任何问题。

如果factory构造函数是未命名的,那么我同意返回null可能是调用者意外的,可能应该避免。

也就是说,在这种情况下,没有太多理由使用factory构造函数而不是static方法,static方法更清晰。

更新

对于迁移到空安全的代码,建议使用static方法返回null。看看我的新答案。

这是一种糟糕的做法。当有人调用构造函数时,他们期望得到一个非null值。

对于您的情况,我可能会用静态方法进行验证:

class EmailAddress {
final String _value;
static final RegExp _regex = new RegExp(r"...");
static bool isValid(String email) => _regex.hasMatch(email);
EmailAddress(this._value) {
if (!isValid(_value)) throw "Invalid email: $_value";
}
}

现在您可以获得代码重用和良好的语义。例如:

querySelector("#sendButton").disabled = !EmailAddress.isValid(userEmail);
请不要这样做。作为构造函数的用户,我希望收到构造函数类的实例。可以在Dart中返回预先存在的实例或子类型的实例,但不要返回null

我建议您在这里选择两个选项之一:

  1. 对无效输入抛出异常。这样,如果您将null存储在某个位置,那么错误至少是早发生的,而不是晚发生的。

  2. 使用静态方法而不是构造函数。静态方法可以返回null,并且不会造成混淆。

  3. 提供后备路径,例如int.parse。您可以接受将在出现错误时调用的回调。

我自己更喜欢1或3。我想明确地知道什么时候有些东西是无效的。

最新更新