我一直在用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
中的内置Factory software concept特征没有任何空值限制。
另一方面,我可以改写你的问题“从等于运算符返回null是否可以接受”
bool operator ==(other) {
return null;
}
这也是可以接受的,因为没有这样的限制,该运算符不能返回null
值。
但还有另一个问题吗?为什么这样做以及如何避免它?
factory EmailAddress(String input) {
return _regex.hasMatch(input) ? new EmailAddress._internal(input) :
throw "something went wrong";
}
附:
我个人认为,从Dart的null
返回factory
是一个bad practice
,因为Dart的工厂很难与指挥官区分开来。
从外面看,它们看起来像是构造函数,区别在于它们更强大,因为它们可以构造不同类型的对象。
他们也有自己的限制,但这是另一个故事......
请不要这样做。作为构造函数的用户,我希望收到构造函数类的实例。可以在Dart中返回预先存在的实例或子类型的实例,但不要返回null
。
我建议在这里做你想做的两个选项之一:
null
存储在某个地方。null
而不是令人困惑。int.parse
。您可以接受将在错误时调用的回调。我更喜欢自己1或3。当某些事情无效时,我想明确地知道。
这是不好的做法。当有人调用构造函数时,他们期望一个非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);
我将不同意其他答案:至少对于命名的factory
构造函数,我认为返回null
没有任何问题。
The main differences between a factory
constructor and a static
method是一个factory
构造函数可以与new
一起使用,可以是未命名的默认构造函数。 Using new
is now discouraged,因此命名的factory
构造函数将无法与调用点上的static
方法调用区分开来。
我没有看到返回static
的null
方法有什么问题,因此我没有看到任何返回factory
的命名null
构造函数有什么问题。
如果factory
构造函数未命名,那么我同意返回null
可能是调用者意外的,可能应该避免。