什么时候应该在 dart 中使用 final 字段、工厂构造函数或带有 getter 的私有字段?
When should final fields, factory constructors or private fields with getters be used in dart?
如果你能弄清楚如何重命名这个问题,我愿意接受建议。
在 Dart 语言中,可以写一个带有 final 字段的 class。这些字段只能在 构造函数 主体运行之前设置。这可以在声明中(通常用于 class 内的静态常量),在声明构造函数或使用 this.field
shorthand:
时的初始化列表语法中
class NumBox{
final num value;
NumBox(this.value);
}
假设我实际上需要对实例创建做一些处理,不能只在构造函数之前初始化字段。我可以切换到使用带有 getter:
的私有非最终字段
class NumBox{
num _value;
NumBox(num v) {
_value = someComplexOperation(v);
}
num get value => _value;
}
或者我可以使用工厂构造函数获得类似的行为:
class NumBox{
final num value;
factory NumBox(num v) {
return new NumBox._internal(someComplexOperation(v));
};
NumBox._internal(this.value);
}
几年前我尝试学习 Dart 时遇到了类似的问题,现在我有了更多的包袱,但我仍然不知道。 更聪明的方法是什么?
工厂构造函数是一种好方法,它允许不受限制地预先计算任何值,然后将这些值传递给普通构造函数以转发到最终字段。
另一种方法是在构造函数主体之前执行的初始化列表,因此允许初始化最终字段:
class NumBox{
final num value;
NumBox(num v) : value = someComplexOperation(v)
}
在初始化列表中你不能读取this
因为实例还没有完全初始化。
您应该在设计 API 时考虑到您的用户,然后以对您来说更简单且更易于维护的任何方式实现它。这个问题是关于后半部分的。
在可能的情况下将字段设置为 final 非常好,而在不可能的情况下,使用 public getter 将它们设置为私有是一个不错的选择。做什么是你的选择,因为维护你的 class 的是你,没有其他人应该需要看 public API.
如果您需要复杂的计算,Günther Zöchbauer 的建议是第一个转向:使用辅助函数。在某些情况下,您甚至可以内联
class MyThing {
final x;
MyThing(args) : x = (() { complex code on args; return result;} ());
}
不过,它很快就会变得丑陋,所以将它作为静态辅助函数通常会更好。
如果您的复杂计算与此不匹配,这通常意味着有多个字段被相关值初始化,那么您需要一个地方来存储中间值并在初始化时多次使用它对象。
工厂构造函数是一种简单的方法,您可以计算所需的一切,然后在最后调用私有生成构造函数。唯一的 "problem" 是通过不公开生成构造函数,您可以防止其他人扩展您的 class。我引用 "problem" 是因为这不一定是坏事——允许人们扩展 class 是一个限制你可以用 class 做什么的合同。
我倾向于使用私有生成构造函数 public 工厂构造函数,即使出于任何实际原因不需要它,只是为了禁用 class 扩展。
class MyClass {
const factory MyClass(args) = MyClass._; // Can be const, if you want it.
const MyClass._(args) : ... init .. args ...;
}
如果你需要一个生成构造函数,你可以使用转发生成构造函数来引入一个具有计算值的中间变量:
class MyClass {
final This x;
final That y;
MyClass(args) : this._(args, _complexComputation(args));
MyClass._(args, extra) : x = extra.theThis, y = extra.theThat, ...;
}
总而言之,没有严格的规定。如果您更喜欢 final 字段,您可以做额外的工作使它们成为最终字段,或者您可以将可变性隐藏在 getter 后面——这是一种实现和可维护性选择,而您是维护代码的人。
只要你保持抽象干净,并跟踪你对用户的承诺(生成构造函数?const 构造函数?)这样你就不会破坏它,你可以随时更改实现。
如果你能弄清楚如何重命名这个问题,我愿意接受建议。
在 Dart 语言中,可以写一个带有 final 字段的 class。这些字段只能在 构造函数 主体运行之前设置。这可以在声明中(通常用于 class 内的静态常量),在声明构造函数或使用 this.field
shorthand:
class NumBox{
final num value;
NumBox(this.value);
}
假设我实际上需要对实例创建做一些处理,不能只在构造函数之前初始化字段。我可以切换到使用带有 getter:
的私有非最终字段class NumBox{
num _value;
NumBox(num v) {
_value = someComplexOperation(v);
}
num get value => _value;
}
或者我可以使用工厂构造函数获得类似的行为:
class NumBox{
final num value;
factory NumBox(num v) {
return new NumBox._internal(someComplexOperation(v));
};
NumBox._internal(this.value);
}
几年前我尝试学习 Dart 时遇到了类似的问题,现在我有了更多的包袱,但我仍然不知道。 更聪明的方法是什么?
工厂构造函数是一种好方法,它允许不受限制地预先计算任何值,然后将这些值传递给普通构造函数以转发到最终字段。
另一种方法是在构造函数主体之前执行的初始化列表,因此允许初始化最终字段:
class NumBox{
final num value;
NumBox(num v) : value = someComplexOperation(v)
}
在初始化列表中你不能读取this
因为实例还没有完全初始化。
您应该在设计 API 时考虑到您的用户,然后以对您来说更简单且更易于维护的任何方式实现它。这个问题是关于后半部分的。
在可能的情况下将字段设置为 final 非常好,而在不可能的情况下,使用 public getter 将它们设置为私有是一个不错的选择。做什么是你的选择,因为维护你的 class 的是你,没有其他人应该需要看 public API.
如果您需要复杂的计算,Günther Zöchbauer 的建议是第一个转向:使用辅助函数。在某些情况下,您甚至可以内联
class MyThing {
final x;
MyThing(args) : x = (() { complex code on args; return result;} ());
}
不过,它很快就会变得丑陋,所以将它作为静态辅助函数通常会更好。
如果您的复杂计算与此不匹配,这通常意味着有多个字段被相关值初始化,那么您需要一个地方来存储中间值并在初始化时多次使用它对象。
工厂构造函数是一种简单的方法,您可以计算所需的一切,然后在最后调用私有生成构造函数。唯一的 "problem" 是通过不公开生成构造函数,您可以防止其他人扩展您的 class。我引用 "problem" 是因为这不一定是坏事——允许人们扩展 class 是一个限制你可以用 class 做什么的合同。 我倾向于使用私有生成构造函数 public 工厂构造函数,即使出于任何实际原因不需要它,只是为了禁用 class 扩展。
class MyClass {
const factory MyClass(args) = MyClass._; // Can be const, if you want it.
const MyClass._(args) : ... init .. args ...;
}
如果你需要一个生成构造函数,你可以使用转发生成构造函数来引入一个具有计算值的中间变量:
class MyClass {
final This x;
final That y;
MyClass(args) : this._(args, _complexComputation(args));
MyClass._(args, extra) : x = extra.theThis, y = extra.theThat, ...;
}
总而言之,没有严格的规定。如果您更喜欢 final 字段,您可以做额外的工作使它们成为最终字段,或者您可以将可变性隐藏在 getter 后面——这是一种实现和可维护性选择,而您是维护代码的人。 只要你保持抽象干净,并跟踪你对用户的承诺(生成构造函数?const 构造函数?)这样你就不会破坏它,你可以随时更改实现。