通常需要在不同的对象/类之间共享相同的数据。我知道有几种不同的方法:
有时,这种数据共享会导致设计对此共享数据的封装较弱。经常出现的两种常见情况如下:
class SharedData
{
public:
double GetVar() const {return var;}
bool GetFlag() const {return flag;}
void SetVar(double in_var) {var = in_var;}
void SetFlag(bool in_flag) {flag = in_flag;}
private:
double var;
bool flag;
};
class StateIface
{
public:
virtual void Run(SharedData* in_shared_data) = 0;
};
class ConcreteStateA : public StateIface
{
virtual void Run(SharedData* in_shared_data) final;
};
class ConcreteStateB : public StateIface
{
virtual void Run(SharedData* in_shared_data) final;
};
此处,ConcreteStateA
等具体实施需要访问SharedData
,例如SharedData
。获取/设置某些数据,可以使用此信息来决定状态转换等。如上例所示,我们可以将SharedData
声明为类并提供访问器/更改器。或者我们可以简单地将SharedData
声明为结构。但是,在这两种情况下,具体实现都可以修改ConcreteStateA
中的任何参数。例如,假设flag
与ConcreteStateA
无关,因此无法改变它。但是,使用给定的接口,我们无法控制该行为。 ConcreteStateB
和ConcreteState
都可以访问所有数据,并可以获取/设置任何参数。这个问题有更好的设计/解决方案吗?一个为共享数据提供更多保护的一个。或者,我们是否可以某种方式强制执行约束,即某个SharedData
只能修改StateInterface
的某些参数,同时仍然可以实现公共class SubroutineInterface
{
public:
virutal void DoSubroutine(SharedData* in_shared_data) = 0;
}
class ConcreteSubroutine : public SubroutineInterface
{
public:
virutal void DoSubroutine(SharedData* in_shared_data) final;
};
?
SQL> SELECT to_date('2018m3', 'YYYY"m"MM') FROM dual
2 /
与状态机示例相同的问题......
答案 0 :(得分:2)
您可以通过SharedData
不透明类型
library.h
class SharedData;
void foo(SharedData*);
class bar {
public:
void method(SharedData*);
};
library_private.h
class SharedData {
public:
int x;
};
library.cpp
#include "library.h"
#include "library_private.h"
void foo(SharedData* d) {
d->x = 0;
}
void bar::method(SharedData* d) {
d->x = 1;
}
这样,只有包含library_private.h的cpp文件才能访问SharedData
的接口,但SharedData
个实例仍然可以在项目的其余部分传递。
唯一棘手的部分是管理SharedData
的生命周期,因为大多数时候你必须在堆上分配SharedData
,智能指针必须附加自定义删除器。因此,opaque类型通常包含在某种包装器类型中以管理RAII。
这样的事情:
标题中的:
class SharedDataImpl;
class SharedData {
public:
SharedData();
~SharedData();
SharedDataImpl* get() {
return impl_.get();
}
private:
std::unique_ptr<SharedDataImpl> impl_;
};
in .cpp:
SharedData()
: impl_(std::make_unique<SharedDataImpl>()) {}
~SharedData() {}
答案 1 :(得分:2)
您可以使用PassKey习语,例如:
class SharedData
{
public:
class FlagKey
{
friend class ConcreteStateA;
// List here classes which can modify Flag
private:
FlagKey() {}
FlagKey(const FlagKey&) = delete;
};
class VarKey
{
friend class ConcreteStateB;
// List here classes which can modify Var
private:
VarKey() {}
VarKey(const FlagKey&) = delete;
};
public:
double GetVar() const {return var;}
bool GetFlag() const {return flag;}
void SetVar(VarKey, double in_var) {var = in_var;}
void SetFlag(FlagKey, bool in_flag) {flag = in_flag;}
private:
double var = 0;
bool flag = false;
};
然后:
class ConcreteStateA : public StateIface
{
public:
virtual void Run(SharedData& data) final {
// data.SetVar({}, 0); // error: calling a private constructor of class 'VarKey'
data.SetFlag({}, false);
}
};