# 从物质的客观实在性看实体属性

从唯物主义角度看物质的唯一性是客观实在性，实体的本质也是物质，同样也具有客观实在性。属性就是客观实在性的具体体现，比如对于汽车而言，车牌号，颜色，厂商等都是其属性，其中一个或者多个属性的组合则可以标识其唯一性。既然存在属性，那就必然也存在与之相对于的操作方法。

我们在前面有介绍过业务实体的构建以及实体与系统间的转换关系，更多的是偏向于宏观上的分析和设计，那么在此阶段主要偏向于实体内部微观层面的描述和设计。在分析送礼物这个用例的时候我们提到，完成这件事情我们需要一些业务实体以及与之对应的系统。每个业务实体对象的职责是不同的，那么我们如何来表示他们的独特性呢？唯一的办法就是通过属性来描述。

我们在[《从生活中来，到生活中去，谈业务实体抽象》](ye-wu-shi-ti-fen-xi)的文中通过分析，得到如图1所示送礼物对应的实体模型，其中描述了若干个实体，如：消息通道，礼物，虚拟货币，用户信息，虚拟物品。虚拟商品这个实体，在“送礼物”这场景中他所对应的属性如下图所示：商品id，名称，入库时间，更新时间，价格，图标。说到这里，有人会问：我们需不需要实现一套电商平台那样的商品管理系统？如果说公司或者部门内有这样的系统，拿来即用当然更好，如果说没有就可以按照现有的需求独立设计，对于未来可能的场景我们需要保证其扩展性，在设计原则里面有个修改关闭，扩展开放就是这个道理。礼物实体则可以用如下属性来表示：收礼物的人，寄礼物的人，商品名称和礼物数量，那么梳理出来的虚拟物品实体和礼物实体之间的关系就如图2所示。

![图1 实体模型](https://1422447769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LuM9BGn-c7ft3h1D5Gf%2F-MMQUlu8f5uqzN36H6Hb%2F-MMQW5WZxTLcxq7tkkop%2Fimage.png?alt=media\&token=ae47ff83-86e6-4175-b50b-9c57bf2d4960)

![图2](https://1422447769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LuM9BGn-c7ft3h1D5Gf%2F-MMQUlu8f5uqzN36H6Hb%2F-MMQWFInV7M4PD5WI223%2Fimage.png?alt=media\&token=96bfc638-5014-45b0-86f5-ba1e65bfbee8)

另外，有人会问，实体图中不是还应该有描述操作属性的方法吗？对，一般书中都会这么写，但是，以我个人的经验，只需要属性描述清楚，基本就可以确定一个实体，方法可写也不可写。

实体属性确定下来后，后面就需要关注怎么存的问题（存储选型）。一般的思路如下图所示：

![图3](https://1422447769-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LuM9BGn-c7ft3h1D5Gf%2F-MMQUlu8f5uqzN36H6Hb%2F-MMQWNX9khMtH8DXN4hq%2Fimage.png?alt=media\&token=f41f2e2f-2aed-4d4e-8419-736c4e074178)

存储选型在整个业务系统的设计中是至关重要的，一般情况下，系统最先出现瓶颈的地方都是存储这块。针对存储选型，我们主要从以下几点来考虑：

1. 数据的读写比是怎样的，是读多写少还是读少写多等，对读/写性能的要求是怎样的，数据是否需要持久化；
2. 实体对象中的数据需要用什么样的数据结构来存储才能满足我们的查询/写入的需求（这主要考验你数据结构的基本功底好不好了），比如你是读多写少还是写多读少，后续的数据量级有多大等；
3. 了解目前市面上的存储组件（mysql，redis，ssdb，mongo，memcache等等）的特性，看看有哪些能够满足我们所设计的数据结构，能够近似满足即可，然后再根据存储组件的特性对我们的数据结构稍作修改。换句话说，我们设计的数据结构是一种理论情况，而已有的存储组件是现实，当理论与现实产生碰撞的时候，需要折中考虑。当然很多时候，都是了解完查询需求，直接跳到了存储组件的选型，在数据存储结构和算法的设计上缺乏思考，这得益于我们日渐成熟的存储组件，减轻了不少思想上的负担，但是无论存储组件如何发展，我们还是需要具备这样思考的意识，因为很多场景下，数据光依靠数据库是不够的，毕竟有IO消耗，出于性能的考虑需要放到内存中；

我们以Goods实体对象为例，从产品层面上分析，用户会频繁请求礼物列表，因此在系统内，此实体对象是读多写少的场景，既然是对查询要求较高，那我们可以想想哪些数据结构具有较高的查询性能，比如，跳表、散列表、树结构。一般场景下，散列表的查询性能较高，为O(1)。

我们确定数据结构后，我们还需要考虑，实体对象中的数据是否需要持久化，由于礼物信息在系统重启后，不能丢失，故需要持久化。然后，我们再去看看市面上的这些流行的存储组件，哪些满足以上两个特性，我们发现redis中的string结构能够跟我们设计的数据结构相契合，而且是内存级数据库，性能好，并支持持久化。

因此，针对Goods实体对象数据的存储，我们选择用redis。这里的case比较简单，我们主要的目的是为了阐述数据选型的思路。

在这里，容易出现的一个问题：有些人不去了解这些数据库底层的实现方案，就轻易做出选择。就如，在redis中string结构，hash结构从功能上都可以满足我们的需求。那么随着数据量的增长，从性能上能否能继续满足我们的需求呢？这就要求我们工程师，知其一，还得知其二。只有深入的了解它，才能更好的使用它。

最后，确定存储方案后，需要进行方案验证。
