3

MessengerClient类上有一个Login函数。MessengerClient类有一个LoggedIn事件和一个IsLoggedIn属性。

当在MessengerClient类上调用Login时,联系人列表/名册通过套接字从远程服务器获取并进行处理,然后认为客户端已登录并且IsLoggedIn将返回 true。LoggedIn事件在此之后的 Login 函数内引发(因此,在请求登录的同一个线程内 - 我不认为这是一件坏事)。

登录后,客户端会在发生时从远程服务器接收实时更新。

在登录期间处理联系人列表/名册时,我相信最终用户的理想设计是在客户端被认为已登录之前处理所有联系人列表/名册数据。这样,当用户收到LoggedIn事件时,他们能够立即访问联系人数据。

例如 -

这里我们有LoggedIn事件的最终用户处理程序。

    void MsgrLoggedIn(object sender, EventArgs a)
    {
        _msgr.Contacts.Contains("billy@bob.com"); //returns true
    }

由于在客户端被标记为已登录之前已处理了所有联系人列表,并且在引发 LoggedIn事件之前,上述语句返回 true。从逻辑上讲,我相信这是最终用户所期望的,因为下载和处理联系人列表是登录操作的一部分。

现在,我还喜欢在将联系人添加到联系人列表或添加到组时引发事件。按照我到目前为止提到的逻辑,在处理数据时引发ContactAddedContactAddedToGroup等事件显然是没有意义的,因为这将导致最终用户在 MessengerClient 类甚至之前收到这些事件之一标记为已登录。

    void MsgrContactAdded(object sender, ContactEventArgs e)
    {
        _msgr.SendMessage(e.Contact, "hello there"); // throws NotLoggedInException
    }

如上所示,会导致坏事发生。

所以我真正需要做的是处理联系人列表数据,引发登录事件,然后引发所有其他联系人事件。

为此,我可以遍历所有联系人对象、组对象等并引发适当的事件。

到目前为止还好,对吧?

然而,问题在于,除了在首次登录时下载联系人列表数据之外,如果客户端注销然后重新登录,我还必须准备同步联系人数据。

这将涉及诸如 ContactRemoved、ContactNameChanged、ContactRemovedFromGroup 等事件。

因此,它不再像遍历联系人、组等那样简单,因为现在我必须考虑已删除或属性已更改的联系人。

所以我需要一种替代方法来“排队”这些事件在登录发生后引发。

我考虑过用类来表示每个同步事件——例如 SyncContactRemoved、SyncContactNameChanged、SyncContactAddedToGroup。有了这个,我可以处理数据,为每个事件创建一个 Sync*XXX* 类,并将它们添加到一个列表中,然后我可以在登录后对其进行迭代。

我还考虑过对对象本身使用方法。即 Group.SyncContactsAdded、Contact.SyncNameChanged、MessengerClient.SyncContactsAdded。然后我可以在登录后遍历联系人/组等,检查这些属性,在必要时引发事件,然后清除它们。

最后,我考虑了一个包含 EventHandler 和 EventArgs 的 Event 类。事件可以以这种方式排队,然后在登录后一一调用。

如果有的话,这些模式中的哪一个会被认为是更常见的做法。还是有其他方法可以实现这一目标?

我为这么长的问题道歉,但这不是一个简单的问题。

谢谢

4

4 回答 4

0

每个联系人都有自己的联系人列表。

public class Contact
{
  List<Contact> Contacts;
}

每个联系人都有自己的事件(PropertyChanged、LoggedIn 等)

public class Contact
{
  List<Contact> Contacts;
  public event OnPropertyChanged;
}

如果Contact 登录,该Contact 将注册到其Contact List 中每个Contact 的所有Events。

public void LogIn
{
  //Load Contact List for User - Do other stuff
  foreach(Contact c in Contacts)
    c.PropertyChanged += new PropertyChangedEventHandler(ContactPropertyChanged);
}

现在,如果联系人列表中发生了某些事情,那些已登录并在列表中有此联系人的人将获得该事件。

public void ChangeProperty
{
  //Change Property and raise event!
}
于 2012-04-14T12:01:16.290 回答
0

这些模式中的哪一种会被认为是更常见的做法。还是有其他方法可以实现这一目标?

因此,如果我直截了当地说,您希望将给定联系人的联系人上发生的所有事件排队,而第一个事件处于脱机状态?所以联系人A的联系人列表中有联系人B,但此时联系人A处于离线状态。现在联系人 B 更改了他的个人资料,并且您想ContactNameChanged为联系人 A 排队该事件(等等)?

我不会那样做的。我宁愿存储某种同步令牌(一个日期时间就可以了),它表明联系人 A 何时收到联系人 B 的数据。然后,每个联系人都有一个LastModified属性,您可以将其与同步令牌进行比较。如果自上次同步后进行了一些修改,请发出请求以获取修改后的联系人的完整详细信息。

对于已删除的联系人,您只需将两个列表相交即可。一个是客户认为是其当前列表的联系人列表,另一个是来自服务器的最新列表。比较这些将导致添加和删除,并且在循环浏览此列表时,您还可以比较上面提到LastModified的 -datetimes。

于 2012-04-18T09:37:03.837 回答
0

我相信你需要看看States设计模式。考虑到客户端每次都有不同的状态,例如:

在此状态下的登录状态将生成一些特殊事件,例如 LoginFailed 或 LoginSucceed,并且此状态将仅提供一种方法 Login。

用户将接受消息并将其发送到组的聊天状态。

以及您需要的任何东西。

因此,您的客户端类将实现特殊状态侦听器接口,该接口将生成有效事件(事件只是接口的方法调用)。

通过这种方式,您将分离不同类中不同状态的逻辑。您将在当前状态下在内部更改状态,因此您的库的用户将无法进行任何破解并使您的库无法正常工作。

我认为这是异步通信实现的最佳解决方案。考虑客户端和服务器端的两个状态机。

实际上它有很多代码,所以我只是给了你这个概念。

http://en.wikipedia.org/wiki/State_pattern

于 2012-04-19T09:05:18.593 回答
0

我最终将事件存储在一个列表中并在之后提出它们。

List<SomethingEventArgs> events;

foreach (SomethingEventArgs e in events)
    OnSomethingEvent(e);

它不像我想要的那样迷人,但它很有意义,而且效果很好。

于 2012-04-26T01:17:24.783 回答