总体设计:我有一个聚合类C
,其中包含N
类型的成员变量M_i, i = 1 ... N
,每个变量都有一个通用的只写 update()
接口以及特定于类的只读访问器函数[F]un_i(), [F] = any letter, i = 1 .. N
(实际上它们没有这样的常规名称)。每个成员类型都M_i
形成了自己的独立抽象,并在我的程序的其他地方使用。
聚合类需要在一个事务中更新所有成员,所以它有一个update()
自己的函数调用它update()
的所有成员变量的成员函数。
// building blocks M_i, i = 1 ... N
class M_1
{
public:
// common write-only interface
void update();
// M_1 specific read-only interface
int fun_1() const;
// ...
int fun_K() const;
private:
// impl
};
// ...
class M_N
{
public:
// common write-only interface
void update();
// M_N specific read-only interface
int gun_1() const;
// ...
int gun_K() const;
private:
// impl
};
// aggregate containing member variables M_i, i = 1 ... N
class C
{
public:
// update all members in a single transaction
void update()
{
m1_.update();
// ...
mN_.update();
}
// read-only interface?? see below
private:
M_1 m1_;
// ...
M_N mN_;
};
问题:我是否可以访问聚合类中各种成员变量的各种成员函数?我可以想到三种选择:
备选方案 1:将N * K
委托写入所有成员变量K
的所有成员函数N
class C
{
int fun_1() const { return m1_.fun_1(); }
// ...
int fun_K() const { return m1_.fun_K(); }
// ...
int gun_1() const { return mN_.gun_1(); }
// ...
int gun_K() const { return mN_.gun_K(); }
// as before
};
int res = C.fun_5(); // call 5th member function of 1st member variable
备选方案 2N
:对所有N
成员变量写入访问器
class C
{
M_1 const& m1() const { return m1_; }
// ...
M_N const& mN() const { return mN_; }
// as before
};
int res = C.m1().fun_5(); // call 5th member function of 1st member variable
备选方案 3:将1
访问器模板写入所有N
成员变量
class C
{
public:
enum { m1, /* ... */ mN };
template<std::size_t I>
auto get() const -> decltype(std::get<I>(data_))
{
return std::get<I>(data_);
}
private:
std::tuple<M_1, /* ... */ M_N> data_;
};
int res = C.get<m1>().fun_5(); // call 5th member function of 1st member variable
备选方案 1 避免违反得墨忒耳定律,但它需要大量繁琐的样板代码(在我的应用程序中,N = 5
并且K = 3
,因此15
委托包装器)。备选方案 2 减少了包装器的数量,但调用代码对我来说有点难看。但是由于所有这些代码都是只读的,并且修改只能通过一致的聚合发生update()
,所以我目前认为替代方案 2 比替代方案 1 更可取(并且至少是安全的)。如果是这种情况,那么更进一步,备选方案 3 应该是最佳选择,因为它只使用一个访问器并且具有与备选方案 2 相同的安全保证。
问题:这种代码的首选接口是什么?