这取决于的实际意义a
,b
和getProduct
。
吸气剂的目的是能够更改实际实现,同时保持对象的接口相同。例如,如果某天getA
变为return a + 1;
,则更改将本地化到一个吸气剂。
实际情况下的案例有时比通过与getter关联的构造函数分配的常量后备字段更为复杂。例如,可以在代码的原始版本中从数据库计算或加载该字段的值。在下一版本中,可能会添加缓存以优化性能。如果getProduct
继续使用计算的版本,则无法从缓存中受益(否则维护者将进行两次相同的更改)。
如果它使完美的意义getProduct
使用a
和b
直接使用它们。否则,请使用吸气剂防止以后出现维护问题。
一个使用吸气剂的例子:
class Product {
public:
Product(ProductId id) : {
price = Money.fromCents(
data.findProductById(id).price,
environment.currentCurrency
)
}
Money getPrice() {
return price;
}
Money getPriceWithRebate() {
return getPrice().applyRebate(rebate); // ← Using a getter instead of a field.
}
private:
Money price;
}
尽管目前,getter不包含任何业务逻辑,但不排除构造函数中的逻辑将迁移到getter,以避免在初始化对象时进行数据库工作:
class Product {
public:
Product(ProductId id) : id(id) { }
Money getPrice() {
return Money.fromCents(
data.findProductById(id).price,
environment.currentCurrency
)
}
Money getPriceWithRebate() {
return getPrice().applyRebate(rebate);
}
private:
const ProductId id;
}
以后,可以添加缓存(在C#中,将使用Lazy<T>
,使代码简短易行;我不知道C ++中是否存在等效项):
class Product {
public:
Product(ProductId id) : id(id) { }
Money getPrice() {
if (priceCache == NULL) {
priceCache = Money.fromCents(
data.findProductById(id).price,
environment.currentCurrency
)
return priceCache;
}
Money getPriceWithRebate() {
return getPrice().applyRebate(rebate);
}
private:
const ProductId id;
Money priceCache;
}
两项更改都集中在getter和backing字段上,其余代码不受影响。相反,如果我在中使用了字段而不是getter getPriceWithRebate
,那么我也必须反映那里的更改。
可能使用私有字段的示例:
class Product {
public:
Product(ProductId id) : id(id) { }
ProductId getId() const { return id; }
Money getPrice() {
return Money.fromCents(
data.findProductById(id).price, // ← Accessing `id` directly.
environment.currentCurrency
)
}
private:
const ProductId id;
}
该getter很简单:它是常量readonly
字段的直接表示形式(类似于C#的字段),预计该字段将来不会更改:机会是,ID getter永远不会成为计算值。因此,请保持简单,并直接访问该字段。
另一个好处是,getId
如果看起来好像没有在外部使用,则将来可能会删除它们(就像在上一段代码中一样)。
const
:我认为这意味着编译器getId
无论如何都会内联调用,并且允许您在任一方向进行更改。(否则,我完全同意你的理由来使用干将。),并且在那些提供物业语法的语言,还有的甚至更少理由不使用属性,而不是直接支持字段。