ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] 在Dart中,对象具有成员,成员可以是函数(方法)或数据(实例变量)。以下最佳实践适用于对象的成员。 ## 不要把不必要地将字段包装在getter和setter中。 在Java和c#中,通常将所有字段隐藏在getter和setter之后(或c#中的属性),即使实现只是转发给字段。这样,如果您需要在这些成员中做更多的工作,您可以不需要接触callsites。这是因为调用getter方法与访问Java中的字段不同,访问属性与访问c#中的原始字段不兼容。 Dart没有这个限制。字段和getter /setter完全无法区分。您可以在类中公开一个字段,然后将其包装在getter和setter中,而不必接触任何使用该字段的代码。 ~~~ class Box { var contents; } ~~~ 以下是不推荐的写法: ~~~ class Box { var _contents; get contents => _contents; set contents(value) { _contents = value; } } ~~~ ## 优先使用final字段来创建只读属性。 如果您有一个字段,外部代码应该能够看到,但不能分配给它,一个简单的解决方案是简单地标记它为final。 ~~~ class Box { final contents = []; } ~~~ 以下是不推荐的写法: ~~~ class Box { var _contents; get contents => _contents; } ~~~ 当然,如果您需要在构造函数外部内部分配字段,那么您可能需要执行“私有字段、公共getter”模式,但是在需要之前不要这样做。 ## 考虑对简单成员使用=>。 除了对函数表达式使用=>外,Dart还允许使用它定义成员。这种样式非常适合于只计算并返回值的简单成员。 ~~~ double get area => (right - left) * (bottom - top); bool isReady(num time) => minTime == null || minTime <= time; String capitalize(String name) => '${name[0].toUpperCase()}${name.substring(1)}'; ~~~ 写代码的人似乎喜欢=>,但很容易滥用它,最终导致难以阅读的代码。如果您的声明超过几行或包含深度嵌套的表达式(级联和条件运算符是常见的攻击者),请您和所有需要阅读您的代码的人帮忙,并使用块体和一些语句。 ~~~ Treasure openChest(Chest chest, Point where) { if (_opened.containsKey(chest)) return null; var treasure = Treasure(where); treasure.addAll(chest.contents); _opened[chest] = treasure; return treasure; } ~~~ 以下是不推荐的写法: ~~~ Treasure openChest(Chest chest, Point where) => _opened.containsKey(chest) ? null : _opened[chest] = Treasure(where) ..addAll(chest.contents); ~~~ 对于不返回值的成员,也可以使用=>。如果setter很小,并且具有使用=>的相应getter,那么这就是惯用方法。 ~~~ num get x => center.x; set x(num value) => center = Point(value, center.y); ~~~ 对于非setter void成员,使用=>不是一个好主意。=>意味着“返回一个值”,因此如果您使用void成员,读者可能会误解它的作用。 ## 在不需要的时候不要用this.以免产生歧义。 JavaScript需要明确这一点。引用当前正在执行其方法的对象上的成员,但是像dart一样的c++、Java和c#没有这个限制。 你唯一需要使用这个的场景是:当具有相同名称的局部变量隐藏您想要访问的成员时。 以下是不推荐的写法: ~~~ class Box { var value; void clear() { this.update(null); } void update(value) { this.value = value; } } ~~~ 以下是推荐的写法: ~~~ class Box { var value; void clear() { update(null); } void update(value) { this.value = value; } } ~~~ 注意,构造函数参数从不在构造函数初始化列表中隐藏字段: ~~~ class Box extends BaseBox { var value; Box(value) : value = value, super(value); } ~~~ 这看起来令人惊讶,但工作起来像你想要的。幸运的是,由于初始化了formals,这样的代码相对少见。 ## 在可能的情况下,对字段的声明进行初始化。 如果字段不依赖于任何构造函数参数,则可以并且应该在声明时初始化它。它需要更少的代码,并且确保如果类有多个构造函数,您不会忘记初始化它。 以下是不推荐的写法: ~~~ class Folder { final String name; final List<Document> contents; Folder(this.name) : contents = []; Folder.temp() : name = 'temporary'; // Oops! Forgot contents. } ~~~ 以下是推荐的写法: ~~~ class Folder { final String name; final List<Document> contents = []; Folder(this.name); Folder.temp() : name = 'temporary'; } ~~~ 当然,如果字段依赖于构造函数参数,或者由不同的构造函数以不同的方式初始化,那么这个指导原则就不适用。