作为一个例子,我有这种情况,其中类A
和B
执行相同的昂贵计算,函数expensiveFunction
。这个函数是“纯粹的”,因为我可以保证它会在给定相同输入的情况下给出相同的结果。客户端可以使用具有相同输入的两个类(或更多类似的类),并且我希望耗费功能仅计算一次。但是,客户端也可能只对给定的输入使用一个类。
代码示例:
class A {
public:
A(const InputData& input) {
res = expensiveFunction(input);
}
void foo(); //Use the expensive result
private:
ExpensiveResult res;
};
class B {
public:
B(const InputData& input) {
res = expensiveFunction(input); //Same function as in A
}
double bar(); //Use the expensive result
private:
ExpensiveResult res;
};
int main() {
//Get some input
//...
A a(input);
B b(input);
//Do stuff with a and b
//More input
A a2(otherInput);
//...
}
在某些语言中,由于引用透明度和memoization,它只能为给定的输入安全地计算一次。
我所想到的是使用某种排序工厂方法/类,或者为存储结果的A
和B
类提供函数对象/ functor / supension。
有什么好的设计理念来解决这个问题?
我拥有所有代码,因此我可以根据需要更改客户端或服务类。
答案 0 :(得分:2)
您可以在功能内部进行记忆
COutput expensive(CInput input) {
static std::map<CInput, COutput> memoized_result;
auto resit = memoized_result.find(input);
if (resit == memoized_result.end()) {
// ... do calculations
output = expensiveCalculation(input);
resit = memoized_result.insert(std::make_pair(input, output));
}
return resit->second;
}
计算结果存储在静态映射(memoized_result)中,并在函数调用之间保持不变。
如果输入太昂贵而无法用作地图中的键,则可以创建一个单独的类来处理计算结果,并在所有客户端之间共享:
#include <memory>
using namespace std;
class ExpensiveResult {
public:
ExpensiveResult(int input) {
out_ = input+1;
}
int out_;
};
class BaseCompResultUser {
public:
BaseCompResultUser(const std::shared_ptr<ExpensiveResult>& res) {
res_ = res;
}
private:
std::shared_ptr<ExpensiveResult> res_;
};
class A : public BaseCompResultUser {
public:
A(const std::shared_ptr<ExpensiveResult>& r) : BaseCompResultUser(r) { }
};
class B : public BaseCompResultUser {
public:
B(const std::shared_ptr<ExpensiveResult>& r) : BaseCompResultUser(r) { }
};
int main() {
std::shared_ptr<ExpensiveResult> res(new ExpensiveResult(1));
A a(res);
B b(res);
return 0;
}
这将强制在对象之间共享计算结果。
答案 1 :(得分:1)
我认为面向对象的解决方法是让expensiveFunction
成为InputData
的成员函数(或InputData
的某个包装器)然后你的问题很多消失了。您只需在ExpensiveResult
中使InputData
成为可变缓存:
class InputData {
private:
mutable std::shared_ptr<ExpensiveResult> result_;
public:
InputData() : result_(nullptr) {}
std::shared_ptr<ExpensiveResult> expensiveFunction() const {
if (!result_) {
// calculate expensive result...
result_ = std::make_shared<ExpensiveResult>();
}
return result_;
}
};
昂贵的计算只在第一次调用expensiveFunction
时完成。如果以多线程方式调用它,则可能必须添加一些锁定。
答案 2 :(得分:1)
如果ExpensiveFunction在A和B中做同样的事情,它似乎不是真正的成员。为什么不是一个功能?
int main() {
//Get some input
//...
res = expensiveFunction (input) ;
A a(res);
B b(res);
//Do stuff with a and b
//...
}