Dart 构造器的六种类型
原文 https://betterprogramming.pub/6-types-of-constructors-in-dart-e810b6d9f354
前言
我们大多数人都知道构造函数是什么以及它是如何工作的。让我们仔细研究一下我们一直使用的六种类型的构造函数
编写干净的代码在每种语言和框架中都很重要,无论您是唯一的开发人员还是团队的一部分。在这里,我将尽最大努力向您介绍尽可能干净的代码原则。太好了!我们开始吧。
正文
构造函数允许我们创建类的不同实例。因为 Flutter 是关于 widget 的,所以构建 widget 需要构造函数。无论您是什么级别的开发人员,您的代码都可能有很多构造函数,因为您可能有很多 widget 。了解何时以及为何使用每种类型的构造函数非常重要。
现代语言中构造对象的方法有很多, Dart 语提供了以下构造函数:
默认、参数化和命名构造函数称为“生成构造函数”,因为它们纯粹生成实例。
默认构造函数
缺省构造函数或“ no-arg 构造函数”不接受任何参数。如果我们没有在类中声明它,Dart 编译器会自动创建它(没有参数)。每当创建类的新实例时,都将调用此构造函数。它不接受任何参数,而是调用超类的构造函数,它也不接受任何参数。
class SettingsIcon extends StatelessWidget {
// Default constructor
SettingsIcon() {
print("Settings Icon is created");
}
Widget build(BuildContext context) {
return IconButton(icon: Icon(Icons.settings), onPressed: () => {});
}
}
- 我应该什么时候用?
例如,如果您想在构造函数中记录某些内容,您可以使用它。但是,我们不应该在构造函数内部做太多的事情。创建一个实例是昂贵的,并且向它添加更多的工作不是一个好主意。将构造函数仅用于类初始化。老实说,我从不使用默认构造函数。编译器为我生成了一个。
参数化构造函数
我们还可以将参数传递给构造函数。这种类型的构造函数称为参数化构造函数。它用于为实例配置变量。我们有时需要一个可以接受一个或多个参数的构造函数。大多数情况下,参数化构造函数用于在实例变量首次创建时为其赋值。
class SettingsIcon extends StatelessWidget {
final double iconSize;
final Color iconColor;
final VoidCallback callback;
final String tooltip;
// Parameterized Constructor
SettingsIcon(this.callback,
{Key? key,
this.iconSize = 18,
this.iconColor = Colors.white,
this.tooltip = "Settings"})
: super(key: key);
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.settings, color: iconColor),
iconSize: iconSize,
tooltip: tooltip,
onPressed: callback);
}
}
在这里,您可以看到我通过添加一个参数化构造函数改进了 SettingsIcon widget 。Dart 还允许您添加可选参数。在我们的示例中,只需要回调函数; 其余的变量是可选的。以下是一些要点:
- 始终从使变量最终化开始。这样,您就可以实现对象的不变性。
- 您可以在构造函数中同时拥有必需参数和可选参数。您甚至可以使用带有默认值的可选参数。在创建类时,这些都是有用的工具。使用它们的方式,对象的意思是使用。
- 在构建 widget 时,始终使用 Key 作为一个可选参数。
- 确保在构造函数中声明变量的顺序保持不变。
- 对参数使用更具描述性的名称,因为构造函数也是文档的一种形式。
命名构造函数
在 Dart 中,您不能定义同名的多个构造函数(无论如何,我从来都不是一个粉丝)。因此,Dart 引入了一个新的构造函数类型,我们可以给它命名。
class SettingsIcon extends StatelessWidget {
final double iconSize;
final Color iconColor;
final VoidCallback callback;
final String tooltip;
// Parameterized Constructor
SettingsIcon(this.callback,
{Key? key,
this.iconSize = 18,
this.iconColor = Colors.white,
this.tooltip = "Settings"})
: super(key: key);
// Named Constructor
SettingsIcon.dark(this.callback,
{Key? key,
this.iconSize = 18,
this.tooltip = "Settings"})
: iconColor = Colors.black,
super(key: key);
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.settings, color: iconColor),
iconSize: iconSize,
tooltip: tooltip,
onPressed: callback);
}
}
这和之前的类是一样的,但是我添加了一个新命名的构造函数 dark,它生成一个黑色图标而不是一个白色图标。除了命名部分,语法是相同的。其他所有规则仍然适用。它的用法也很简单。
AppBar(title:
Row(children: [
Text(widget.title),
SettingsIcon(() => {}, iconColor: Colors.black, tooltip: "Go to Settings Page"),
SettingsIcon.dark(() => {}, tooltip: "Go to Settings Page")
]))
Dart 构造函数在设计类时给了我们很大的力量; 然而,掌握它们的使用需要时间。我坚信命名构造函数可以提高代码的可读性,但是不应该过度使用。
请参阅 Flutter 的 ListView 实现来获得一个很好的例子:
- ListView.builder
- ListView.separated
- ListView.custom
参数化构造函数从 widget 列表中创建一个可滚动的 widget 。但是,您通常使用 ListView 来拥有具有不同数据的相同 widget ,ListView.builder 启用了这一功能。
请记住,这是一种意识形态上的差异,而不是结构上的变化。结果仍然是一个可滚动的 widget 列表,但是构建的方式不同。我的意思是,创建 ListView.dark 构造函数在这种情况下毫无意义。应该建立一些更基本的东西。
工厂建造商
首先,“工厂”这个词指的是工厂设计模式,它允许构造函数根据传入的参数返回子类的实例(而不是类的实例)。
工厂构造函数只需返回类类型的实例或实现其接口的实例。这可以是该类的新实例、该类的现有实例以及子类的新实例或现有实例。工厂必须使用 return 关键字,并且可以决定返回什么对象。
class SettingsIcon extends StatelessWidget {
final double iconSize;
final Color iconColor;
final VoidCallback callback;
final String tooltip;
// Parameterized Constructor
SettingsIcon(this.callback,
{Key? key,
this.iconSize = 18,
this.iconColor = Colors.white,
this.tooltip = "Settings"})
: super(key: key);
// Named Constructor
SettingsIcon.dark(this.callback,
{Key? key, this.iconSize = 18, this.tooltip = "Settings"})
: iconColor = Colors.black,
super(key: key);
// Factory Constructor
factory SettingsIcon.create(VoidCallback callback,
{double iconSize = 18, String tooltip = "Settings"}) {
return AppTheme.uiConfiguration == UIConfiguration.dark
? SettingsIcon.dark(() {}, iconSize: iconSize, tooltip: tooltip)
: SettingsIcon(() {}, iconColor: Colors.white, iconSize: iconSize, tooltip: tooltip);
}
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.settings, color: iconColor),
iconSize: iconSize,
tooltip: tooltip,
onPressed: callback);
}
}
为了保持一致性,我保留了相同的例子,并添加了一些内容。因此,我添加了一个名为 SettingsIcon.create 的工厂构造函数。它检查一些配置设置,然后根据发现的内容创建一个新实例。您可以使用静态方法实现同样的目的,但是静态方法服务于更通用的目的,而工厂方法必须返回类的实例或其子类之一。
工厂方法是隐藏类的用户正在调用静态方法而不是构造函数这一事实的好方法。如果您将类的实例保存在内存中,但是不想每次都创建一个新实例(或者如果创建一个实例代价高昂) ,那么这可能是工厂方法的一个选项。但是,请记住,您不能从这个构造函数访问 this 关键字,因为它在静态作用域中。
重定向构造函数
在构造函数的右侧,我们可以使用 this 关键字将一个构造函数重定向到同一类中的另一个构造函数。
// Parameterized Constructor
SettingsIcon(this.callback,
{Key? key,
this.iconSize = 18,
this.iconColor = Colors.white,
this.tooltip = "Settings"})
: super(key: key);
// Named Redirecting Constructor
SettingsIcon.dark(VoidCallback callback,
{Key? key, double iconSize = 18, String tooltip = "Settings"})
: this(callback,
key: key,
iconColor: Colors.black,
iconSize: iconSize,
tooltip
: tooltip);
- 请记住,重定向构造函数不需要主体来工作。
- 不能在字段初始值设定项中使用这个关键字,仍然可以使用将被重定向的默认值。
常量构造函数
你也可以在 Dart 中创建常量构造函数,这是什么意思?
如果类表示的对象在创建后永远不会更改,则可以使用常量构造函数。必须确保类的所有字段都是 final 字段。
因为我们在示例中使用了 final 字段,所以我们的构造函数可以是常量字段。我们只需将 const 添加到构造函数定义中。
class SettingsIcon extends StatelessWidget {
final double iconSize;
final Color iconColor;
final VoidCallback callback;
final String tooltip;
// Parameterized Constructor
const SettingsIcon(this.callback,
{Key? key,
this.iconSize = 18,
this.iconColor = Colors.white,
this.tooltip = "Settings"})
: super(key
: key);
使用字段初始值设定项时,必须确保使用常数值。让你的课程尽可能难以改变是一种很好的练习。
小结
- 避免使用缺省构造函数,因为编译器会生成一个。
- Key? Key 应该始终是 flutter widgets 的一个可选参数。
- 尝试使您的构造函数没有代码。Dart 已经尝试通过提供没有主体的字段初始化器和构造函数来推动您实现这一良好实践。
- 使用构造函数的右边进行断言。
- 参数化构造函数可以很好地工作于类的基本函数。根据对象的使用方式使用必需参数和可选参数。
- 使用命名构造函数来提高可读性,但不要过度使用它们。
- 使用工厂构造函数隐藏创建逻辑或在缓存中存储昂贵的对象。
- 不要重复相同的参数结构,而是使用重定向构造函数。
- 始终要考虑类的不变性,并使构造函数为常数。
结束语
如果本文对你有帮助,请转发让更多的朋友阅读。
也许这个操作只要你 3 秒钟,对我来说是一个激励,感谢。
祝你有一个美好的一天~
© 猫哥
微信 ducafecat
https://wiki.ducafecat.tech
https://ducafecat.com