C++ 如何处理同时设置成员的getter?
我正在处理的事情是这样的: 我有一个相当复杂的类和一个成员,它依赖于一些在初始化类时没有设置的东西,或者是在运行时设置的东西。即使未设置该成员,该类的对象也有意义。它也可以根据对其他成员所做的其他更改进行重置 现在,假设这个“特殊”成员的设置在计算上非常昂贵,所以我会根据请求延迟计算它 因此: 我不想每次更改C++ 如何处理同时设置成员的getter?,c++,design-patterns,constants,getter,C++,Design Patterns,Constants,Getter,我正在处理的事情是这样的: 我有一个相当复杂的类和一个成员,它依赖于一些在初始化类时没有设置的东西,或者是在运行时设置的东西。即使未设置该成员,该类的对象也有意义。它也可以根据对其他成员所做的其他更改进行重置 现在,假设这个“特殊”成员的设置在计算上非常昂贵,所以我会根据请求延迟计算它 因此: 我不想每次更改x或y时都调用compute方法,因为它很昂贵,所以我左右为难: 删除常量?从逻辑上讲,getter应该是const,但它不能。还有一个缺点是它不能在const对象上调用 我可以使spec
x
或y
时都调用compute
方法,因为它很昂贵,所以我左右为难:
- 删除
?从逻辑上讲,getter应该是常量
,但它不能。还有一个缺点是它不能在const
对象上调用const
- 我可以使
specialObject
,但这似乎不是正确的做法可变
- 抛弃康斯特内斯?再一次,看起来很可疑
- 在获取之前调用
如果有人忘了怎么办?他们会得到一个过时的结果李>computeSpecialObject
注意:我已经使成员
可变
,想知道是否有更好的解决方案。我会保留常量
,或者使特殊对象
可变,或者保留指向特殊对象
的指针,而不是将其“嵌入”到类中
我还将添加一个booldrity
标志,该标志是可变的
,并在任何更改使计算无效时设置它。然后,我会检查computeSpecialObject
中的标志,并仅在设置了该标志后才执行该工作。使用指针,您甚至可以在更改使现有计算无效时删除旧的计算对象,但这会打开另一整罐蠕虫
还是我遗漏了什么
我可以使specialObject可变,但这似乎不是正确的做法
为什么会这样?这正是mutable
存在的原因:允许const
函数在逻辑上const
而不需要物理上保持对象不变(如果您使对象mutable
,请记住-我相信您知道我的意思)
当然,只要SpecialClass
对象的初始化不会改变对象的逻辑状态,这是正确的,因为const
承诺不会这样做
在这种情况下,函数本身在本质上并不是常量,它的名称应该与getSpecialObject()不同:computeAndReturnSpecialObject()
。,和之相比,在调用方中引入了漏洞,这意味着它可能不存在,并且返回了错误的结果
我将把compute移到特殊对象的方法,并将该类作为该类的compute方法的参数的包装器。一个额外的问题是你可以对计算进行单元测试
然后,这只是一个决定何时需要再次调用SpecialObject.Compute(x,y)或只返回最后一个结果的问题。
如果可以的话,我可以考虑的另一件事是,如果X改变了,但是Y没有改变,我可以简化计算。i、 保留一些中间结果
我不知道它对你有多适用,但我经常做的一件事就是注入一个可以进行计算的东西,所以我在默认情况下倾向于采用这种模式。你可以朝两个方向走,更多的OOP
或更多的功能性
。一个涉及更少地关心状态操纵,而是行为,另一个则完全忘记行为,关心返回的状态
哎呀
对我来说,一个关键的OOP
原则是Tell,not Ask
,或write no getter或setter
设计你的对象,让他们知道你要做什么,让他们自主。不要要求它返回一些你可以用来做某事的对象。让它先做你想做的事。如果你告诉一个对象去做某事,那么你很可能期望它改变状态,而它是const
,这是不对的
您的SpecialClass
可能会提供一些服务doService()
。相反,您可以将Class
告诉doSpecialService()
,这是可以更改的
另一种方法是创建此对象时使用其他对象进行创建。因此,函数可以是常量,但可以采用非常量参数:
class Class {
public:
void doService(ServiceProvider& serviceProvider) const {
serviceProvider.doService(x, y);
}
};
这样,您将传入一个SpecialServiceProvider&
,它将为给定的X
和Y
创建正确的SpecialClass
。它是可变的。在提供服务时修改状态似乎是正确的。也许您可以为(X
,Y
)对使用映射缓存SpecialClass
对象
功能的
另一个方向是使对象不可变。无论何时,只要您想要一些新状态,就可以使用旧状态作为基础来创建它。这可能会产生连锁反应,直到你(几乎)一路上都有海龟:
class SpecialBuilder {
public:
SpecialBuilder withX(const X& newX) const;
SpecialBuilder withY(const Y& newY) const;
SpecialClass build() const;
};
SpecialBuilder specialBuilder;
SpecialClass special = specialBuilder.withX(x).withY(y).build();
您可以在每个返回的SpecialBuilder
之间共享数据,因为它是不可变的。是的,我知道,似乎是合理的,我只是觉得添加mutable
:(@LuchianGrigore:可能是因为它确实改变了对象的逻辑状态。如果specialObject
被初始化,是否有逻辑行为发生变化的函数?比如,当
class SpecialBuilder {
public:
SpecialBuilder withX(const X& newX) const;
SpecialBuilder withY(const Y& newY) const;
SpecialClass build() const;
};
SpecialBuilder specialBuilder;
SpecialClass special = specialBuilder.withX(x).withY(y).build();