这是一个广泛的问题,但根据我自己的理解,我决定将它扔出去。
任何人都可以推荐设计,或者甚至是普遍接受的设计模式,以便人们想要彼此了解的各种物体吗?
要使用人/社区模拟作为类比,当您拥有X可以动态增长/收缩的X对象并让每个人对象持有其他人的意见或关系时,应用的最佳模式是什么对象
在编程语法之外思考,我可以只有一个X×X网格来表示每个人彼此之间的关系(喜欢,不喜欢,没有遇到等等)。我想基本上在代码中实现它作为每个人对象的单独对象,每次创建新对象时都会更新,但它似乎是一个完全不优雅的解决方案。有没有人在这里有任何建议?
其次,如果我收集的每个人都有“库存”或他们携带的物品,我认为我可以创建每个人的库存作为班级的List成员;这个链表会随着人们成长和缩小的对象而增长和缩小。
人们可以很容易地查询人物对象所携带的物体,但我无法找到一种有效的方法来使反之亦然;也就是说,我希望能够查询项目并找到哪些人拥有该项目。
我确实读过这个Q-A: Game Objects Talking To Each Other ..但我不确定它是否完全适用于我的情况。
有人可以提供任何建议吗?
谢谢!
- R的
答案 0 :(得分:1)
完全为此目的制作了关系数据库。如果你不熟悉它,请阅读它!
您可以使用包含多个表的数据库。一张桌子就是“人”,它拥有人的基本属性和身份证。
要为“met”之类的关系建模,请创建一个名为met
的表格,其中包含2列,其中包含两个相互认识的人的ID。
数据库针对诸如“找到遇到约翰的所有人”之类的查询进行了大量优化。如果您不想安装客户端/服务器数据库,可以使用基于文件的数据库,如SQLite
答案 1 :(得分:1)
如果这种关系只是沟通,而不是实际的终身所有权,并且你不希望每个人都能够自动与所有人交谈,那么接口代理通常是一个良好的开端。这些只是中间类,它们拥有与同事沟通的方式,并在任何一方的生命周期发生变化时提供通知。这些通常是单向的,但是当你配对它们并添加更多的胶水代码时,它们就会变成双向的。
所以,你有一个班级
class ColleagueProxy
{
private:
// a pointer to the Colleague
// it can be a naked pointer since it does not deal with lifetime
Colleague friend_;
// a callback for when death comes to the colleague
typedef std::function<void (ColleagueProxy *)> DeathHandler;
DeathHandler deathCallback_;
// an identifier for friends to know me by
std::string id_;
public:
// ctor takes a colleague and a callback for when colleague dies
// ctor notifies friend of new proxy following - in case that is useful info
ColleagueProxy(Colleague * friend, DeathHandler callback, std::string const& myName) :
friend_(friend),
deathCallback_(callback)
{
if (friend)
friend_->proxyConnecting(this);
}
// dtor may notify friend as well
~ColleagueProxy()
{
if (friend)
friend_->proxyLeaving(this);
}
// the communication interface
void sayHi()
{
if (friend)
friend_->sayHi(this);
}
// ...
// my name badge
std::string id() { return id_; }
// a way for the friend to say goodbye
void Goodbye()
{
deathCallback_(this);
}
};
然后同事们将存储这些通信代理
class Colleague
{
private:
std::map<std::string, std::shared_ptr<ColleagueProxy>> friends_;
std::vector<std::shared_ptr<ColleagueProxy>> colleaguesWhoConsiderMeAFriend_;
void GoodbyeCallback(ColleagueProxy * that)
{
// search through friends_ and remove that
}
}
您可以通过管理器类自动执行某些清理部分,因此如果您有不同的动态类型,则不要复制代码。但是,如果你有一个同事类型,那就不是必需的了。经理类可能有用的另一个有用的原因是它可以创建同事,这可能会应用限制或其他可见性规则。
这种设计的关键是允许每个连接可以定制的通信机制(每个代理对象可以保持特定于连接的状态)。这可以应用于意见(如在原始问题中)和许多其他事情。您不必担心循环依赖,因为生命周期管理不是连接的一部分(例如,如果您只是将一个带有shared_ptr的结构存储给朋友,其中循环依赖可能会导致孤立周期问题。)
如果你真的想让每个人都没有限制地看到其他人,那么就不需要在Colleague类中存储Proxies,而是首选经理类。然后所有通信都通过管理器进行,管理器就像代理集合一样。在这些情况下,管理同事生命周期的同一经理可能也扮演代理经理的角色,以防止重复数据和优化访问。
答案 2 :(得分:1)
您正在寻找的是一种相对简单的关联。
class Person {
struct Relationship {
// whatever
};
std::map<Person*, Relationship> relationships;
public:
Person() {}
void Meet(Person* other) {
// think about it
relationships[other] = ...;
}
~Person() {
// Loop through the map and ensure no dud relationships
for(auto& pair : relationships) {
pair.first->relationships.erase(this);
}
}
};
至于确定具有某些项目的人,我认为(相对)简单的经理人解决方案应该运作良好,尽管我讨厌称“经理”课程。
class PersonManager {
struct Item { ... };
std::set<Item, std::set<Person*>> items; // set for no dupes
public:
void AddToInventory(Item i, Person* p) {
items[i].insert(p);
}
std::vector<Person*> PeopleWithItem(Item i) {
return std::vector<Person*>(items[i].begin(), items[i].end());
}
};
如果你必须以这种方式建立 lot 关系的模型,我建议你去一个数据库。但是,我怀疑任何数据库都可以匹配此代码的效率 - 您甚至可以使用哈希容器并为大多数这些操作获取O(1)。
答案 3 :(得分:0)
GOF书中的规范示例是使用Mediator模式。他们提供的示例是GUI窗口/对话框(Mediator)跟踪其控件(有时称为同事),并通知相关事件的控件,例如窗口大小调整等。我相信示例扩展到允许控件查询介体以获取有关其他控件的信息。
如果希望对象能够跟踪特定的对象实例,Observer模式(如cbamber85所示)非常有用。但是对于一般有关对象群体中发生的事件的信息,您可能需要考虑使用Mediator。
关于您的具体问题,调解员可能有助于跟踪一般人群的变化(增长或萎缩)。