我的问题:如何在不担心数据完整性的情况下更好地设计所描述的类?
我有一个Player-Container和Player类。 Player-Container或多或少是一个集中的播放器“数据容器”,对于许多线程,它们都有指向这个类的指针。 TBB库提供了只读和写入的锁定机制。我有一些伪代码来反映我当前的设计:
Class: Player-Container
Method: CreatePlayer, RemovePlayer , LoginUser, VerifyUser
Class: Player
Method: None its a pure data container
现在对我而言,我开发的越多,在“顶级容器”上使用这些功能似乎是错误的,但我似乎没有解决这个问题,因为容器将确保我可以锁定对象以便不进行并行访问可以修改用户(例如,User Builds something并发送此请求两次,资源减少两次而不是一次)。
我想拥有什么:
Class: Player-Container
Method: CreatePlayer, RemovePlayer
Class: Player
Method: LoginUser, VerifyUser,....
我的问题,我如何实现这一点并且仍然是数据完整性保存,我应该只使用hash_map作为“索引”并构建“播放器”级别锁定?有一些意见和建议会很酷。最让我烦恼的是PlayerContainer实际上需要了解Player类,如果我更改了一个属性,我必须在Container中重新编码。
如果有些事情似乎不清楚,请询问。
答案 0 :(得分:2)
听起来你真的有两个问题在这里设计&锁定并且在封装和内聚方面存在很明显的设计张力。
对于api的用户来说,想要只处理'Player-Container'类来添加/删除/登录播放器似乎很不错。
我会考虑在Player-Container上保留前置方法以保持简单。但是我也可能会添加辅助类或辅助函数来实现它们,以确保Player-Container类中的代码非常少。如果您愿意,也可以将这些方法添加到播放器类中。
如果您还没有阅读Scott Meyer关于放置功能的地方的this article,那么它可能值得你花时间。
第二个问题是关于锁定,即锁定在容器或玩家类别上的位置。
这里有选择,但请记住,您需要同步容器和单个类中的数据。因此,如果您使用并发容器来保持玩家并避免对玩家容器类进行重量级锁定,那么您肯定需要确保玩家类同步,特别是如果您允许多个线程在同一个玩家上运行。
如果你这样做,请小心,不要锁定播放器上的各个方法,而是整个播放器,以确保不交错不兼容的功能,即你真的不要不希望LoginUser与同一用户上的RemoveUser同时运行,您可能希望它们序列化并逐个运行。
答案 1 :(得分:1)
我不知道TBB库的特定功能,但一般来说,您可以构建类似SharedObject<Player>
类的东西来公开Player
个实例以及一个锁定对象(例如读取/写mutex)可以使用SharedObjectAccessor对象单独访问,该对象处理正确应用锁。
template<typename T>
class SharedObjectAccessor;
template<typename T>
class SharedObject
{
public:
SharedObject(const T& initial = T())
: managedObject(initial)
{}
private:
friend class SharedObjectAccessor<T>;
const T& read() const { return managedObject; }
T& write() { return managedObject; }
ReadWriteMutex lock;
T managedObject;
};
template<typename T>
class SharedObjectAccessor
{
public:
SharedObjectAccessor(SharedObject<T>& ref)
: sharedObject(ref)
{}
~SharedObjectAccessor() { sharedObject.lock.unlock(); }
const T& get() const
{
sharedObject.lock.lock_read();
return sharedObject.read();
}
T& set()
{
sharedObject.lock.lock_write();
return sharedObject.write();
}
private:
mutable SharedObject<T>& sharedObject;
};