💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
![](https://box.kancloud.cn/60bb00760aac210a5d8be700d347da2b_264x291.jpeg) ``` class Person { get name() {...} set name(aString) {...} ``` ![](https://box.kancloud.cn/a3bed334e2e1f6d1a46c5039deb25af9_91x152.jpeg) ``` class Person { get name() {...} ``` ### 动机 如果为某个字段提供了设值函数,这就暗示这个字段可以被改变。如果不希望在对象创建之后此字段还有机会被改变,那就不要为它提供设值函数(同时将该字段声明为不可变)。这样一来,该字段就只能在构造函数中赋值,我“不想让它被修改”的意图会更加清晰,并且可以排除其值被修改的可能性——这种可能性往往是非常大的。 有两种常见的情况需要讨论。一种情况是,有些人喜欢始终通过访问函数来读写字段值,包括在构造函数内也是如此。这会导致构造函数成为设值函数的唯一使用者。若果真如此,我更愿意去除设值函数,清晰地表达“构造之后不应该再更新字段值”的意图。 另一种情况是,对象是由客户端通过创建脚本构造出来,而不是只有一次简单的构造函数调用。所谓“创建脚本”,首先是调用构造函数,然后就是一系列设值函数的调用,共同完成新对象的构造。创建脚本执行完以后,这个新生对象的部分(乃至全部)字段就不应该再被修改。设值函数只应该在起初的对象创建过程中调用。对于这种情况,我也会想办法去除设值函数,更清晰地表达我的意图。 ### 做法 - 如果构造函数尚无法得到想要设入字段的值,就使用改变函数声明(124)将这个值以参数的形式传入构造函数。在构造函数中调用设值函数,对字段设值。 > 如果想移除多个设值函数,可以一次性把它们的值都传入构造函数,这能简化后续步骤。 - 移除所有在构造函数之外对设值函数的调用,改为使用新的构造函数。每次修改之后都要测试。 > 如果不能把“调用设值函数”替换为“创建一个新对象”(例如你需要更新一个多处共享引用的对象),请放弃本重构。 - 使用内联函数(115)消去设值函数。如果可能的话,把字段声明为不可变。 - 测试。 ### 范例 我有一个很简单的`Person`类。 ##### class Person... ``` get name() {return this._name;} set name(arg) {this._name = arg;} get id() {return this._id;} set id(arg) {this._id = arg;} ``` 目前我会这样创建新对象: ``` const martin = new Person(); martin.name = "martin"; martin.id = "1234"; ``` 对象创建之后,`name`字段可能会改变,但`id`字段不会。为了更清晰地表达这个设计意图,我希望移除对应`id`字段的设值函数。 但`id`字段还得设置初始值,所以我首先用改变函数声明(124)在构造函数中添加对应的参数。 ##### class Person... ``` constructor(id) { this.id = id; } ``` 然后调整创建脚本,改为从构造函数设值`id`字段值。 ``` const martin = new Person("1234"); martin.name = "martin"; martin.id = "1234"; ``` 所有创建`Person`对象的地方都要如此修改,每次修改之后要执行测试。 全部修改完成后,就可以用内联函数(115)消去设值函数。 ##### class Person... ``` constructor(id) { this._id = id; } get name() {return this._name;} set name(arg) {this._name = arg;} get id() {return this._id;} set id(arg) {this._id = arg;} ```