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();