从我个人的理解,评论顾名思义,一般是由一个主题引发出来的一系列的讨论。

从现在的微博、百度贴吧、知乎等来看,评论系统一般来说可由多个小的部分组成,不同产品一般分别含有以下若干种小的功能,如评论主题、对评论进行回复、互评、点赞、举报、删除评论、查看两个人的会话列表。

本质上来看,如果把主题和每一条评论都抽象成一个节点,整个系统构成了一棵树,下面以微博为例做一次简单的模仿设计。

1

针对上图中的微博系统做一些形式化抽象与定义:

  • 主题是一个节点
  • 每一条评论是一个节点
  • 评论、主题的发布人信息、点赞信息等都认为是节点的属性
  • 直接对主题进行的评论叫直接评论
  • 在直接评论下面的评论叫子评论

显然会得到如下结论:

  1. 以主题节点为根可以构造一颗树
  2. 以直接评论为根节点可以构造一个子树,
  3. 所有子树和主题节点构成以主题节点为根的树。

抛开主题节点,对每个评论节点抽象,设计出如下的数据结构(c 代码表示节点中的属性):

typedef struct {
  int id;
  int replied_id; //被评论的id
  int replied_root_id;//直接评论的ID,不是主题的id
  char * content; //评论的内容
  
} CommentNode;

现在根据这个简单的数据结构怎么实现互评、评论功能?仔细观察不难发现,构造规则其实很简单,如下:

  1. 如果节点为直接评论节点,replied_id,replied_root_id 直接置为0
  2. 如果为子评论,则 replied_id 为被回复的评论id, replied_root_id 为所在的直接评论id

现实中经常有一条信息可能会由于种种原因会被删除。那我们是否是就真的要删除这个节点呢?

直接删除节点会引出其他一些问题。

首先,整个树形结构将被破坏,结构出现不完整。 其次,本节点为根节点的子树中其他节点将丢失父节点信息。

删评论的本质并不是删的这个节点,而是要清空这个节点的内容。直接的方式就是清空content字段的内容,并增加一个字段表示节点的状态。

如下所示设置一个color 枚举字段,用于对节点着色,用以表示不同的节点的状态。达到了删评论的目的,同时保留了结构的完整性。


typedef enum{
  GREEN, //表示节点正常
  RED,//表示节点被删除
}NodeColor;

typedef struct {
  int id;//所有的值 > 0
  int replied_id; //被评论的id
  int replied_root_id;//直接评论的ID,不是主题的id
  char * content; //评论的内容
  NodeColor color;
} CommentNode;

类似赞成数、反对数的等功能,在这个基础上额外的增加两个字段就简单的实现这个功能,但也会有一致性的问题存在其中,此处不再赘述。

对于会话列表这个功能应该怎么实现呢?会话列表从形态来看就是两个人直接互相回复的评论构成的对话流。在节点中增加发评论用户和被评论用户两个基础的用户信息比如user_id即可。

typedef enum{
  GREEN, //表示节点正常
  RED,//表示节点被删除
}NodeColor;

typedef struct {
  int id;//所有的值 > 0
  int replied_id; //被评论的id
  int replied_root_id;//直接评论的ID,不是主题的id
  char * content; //评论的内容
  NodeColor color;//节点状态
  int from_user_id; //回复人id
  int to_user_id; //被回复的用户id
} CommentNode;

程序设计的关键在数据结构的设计,良好的数据结构设计往往能起到事半功倍的效果。在评论系统设计的过程中,每当需要增加一个新功能的时候,就去扩充一下数据结构,对应的功能就能得到扩充,修改成本不大,也保证了前向兼容。

以上就是在设计评论系统实现中的一点简单的个人总结。