定义
一切计算机程序,不过是对人类头脑中的现实世界抽象的一种形式化描述。因此,也就是说,程序根源于人类对现实世界的抽象。这种抽象即模型。比如说,人在认识一个东西是否是猫的时候,会用猫的抽象去比对,以比较现实世界的这个东西是否符合心中对猫的抽象——猫的模型,假如说,他认为两者是契合的,那么,该东西就会被打上猫的标签。在这一整个过程中,出现了两样东西,即模型——心中对于所有的猫的一种抽象——和实例——那个符合猫的模型的现实世界的东西。
然而,人类的心中还有千千万万的模型,诸如狗的模型,猪的模型等。这些模型之间的比较不能依赖于实例的比较。实例的比较只能说明实例的不同而不能说明模型的不同。当我们在讨论猫和狗的区别的时候,我们说的并不是某一只猫和某一只狗的区别(当然,一些哲学家恰好持有相反的论点。但是在一般人的概念里,他比较狗和猫的区别,虽然心中浮现的是具体的猫和具体的狗,但是实际上他认为他比较的是抽象的猫和狗。),而是说的是心中猫和狗的模型的差别。
比如说,我们说猫的叫声是喵喵叫,而狗的叫声是汪汪叫,说的不是邻居家的狗和自己家的猫,而是指一种普遍性的比较。这种比较只能是模型的比较。而要比较两个东西,我们首先需要一个对于这两个东西的描述,因为,如果我们无法描述一个东西,显然不能比较它与别的东西。也就是说,我们要比较两个模型,就得首先有两个模型的描述。这种描述即元数据。
因此,模型是一种普遍的概念,是对于某一类事物的抽象;实例则是模型的具体的例子,也可以说是我们借以抽象出模型的那些个独特的事物;而元数据,则是对模型的一种描述。
模型的模型
此外,还有一种特殊的东西,即模型的模型。模型既然是一种现实的东西,它虽然只是一种纯粹的思维的产物,也就是说在现实中找不到任何一个模型,但是这并不妨碍模型会产生模型。也就是说,不妨碍我们对模型进行进一步的抽象,得到“模型的模型”。在猫和狗的例子中,我们可以对猫和狗的模型进行进一步的抽象。假如说,我们的狗的模型就是“叫声是汪汪的”,而猫的模型就是“叫声是喵喵的”,当我们要进一步抽象的时候,我们抽象的其实就是“叫声是汪汪的”的和“叫声是喵喵的”这两个分别对狗和猫的模型的描述。于是我们可以得出,猫和狗的模型的模型就是“描述了叫声的模型”。
这里有一个很模糊的地方。就是,假如我们对狗和猫的模型进行抽象,能否得到动物的模型。也就是说,能否认为动物模型是猫模型和狗模型的模型。这是一个很微妙的问题。对此,我的答案是不能。因为就从猫和狗的例子来看,抽象出来的动物模型是“会叫的东西”。这两者抽象的对象明显不同,一个是对模型的抽象,一个是对所有的猫和狗的实例的抽象。也就是说,猫和狗的模型的模型,是对模型的抽象;而动物的模型,是对猫和狗的实例的抽象。
我用Java来说明这个问题。我们对猫和狗的抽象,对应的是猫和狗的类,而对猫和狗的类的抽象,应该是Java中的Class类。而动物的抽象应该是一个动物的类。显然动物的类不等于Class类。动物的抽象和猫与狗的抽象之间的关系,应该是继承,具体化的关系而不是实例化的关系。
**商品模型的例子
**
在电商中,很重要的一个需求是建立一个商品系统。在商品系统的演进过程中,最开始可能只是为每一个单独的商品类型都建立一个模型(这个可能对应于数据库的一张表,或者代码中的一个类),但是当商品类型多了之后,会发现这种方式基本上无法工作(考虑一下淘宝上面成千上万的商品类型以及依旧还在源源不断产生的新的类型)。
这种情况下,才催生了对于模型的模型的探讨和设计。也就是,我们需要一个模子,这个模子能批量生产不同的商品类型。这就如同我们定义了一个商品类型作为模子,而后生产了千千万万的该类型的商品。
要能够创造这么一个模子,首先要解决的问题是对所有商品类型的抽象。首先,要先仔细区分一个商品类型所必然要有的东西。比如说,一个商品类型要有名字,例如“手机”。然后还有一些个性化的东西,比如说手机类型可能会有一个“内存大小”的属性。这些属性都是对商品类型的抽象。必备的属性和可选的属性有一个很重要的区别,就是必备的属性在商品类型里面其值是确定的,而可选的属性,其值是不确定的。通常来说,抽象的对象涵盖的范围越多,那么必备的属性就越少,而可选的属性就越多。(如果对整个世界的商品类型进行抽象,大概只有名字一个是必备的了)
暂时不需要理会什么是必备的属性和可选的属性。我们需要从前面的结论进一步探讨,对商品类型建模,究竟是建立什么。显然,对于必备属性来说,我们需要给它们一个值,例如某个具体商品类型(模型的实例)的名字;对于可选属性,我们需要将所有可能的可选属性列出来。如果我们排除必备属性和可选的属性的区别,那么可以统一抽象为,创建某个商品类型,就是指明这个商品类型有些什么属性,并且这些属性可以取的值为什么。依旧使用手机的例子。在创建这个手机类型的时候,我们需要给出手机会有什么属性,比如说,手机有品牌,颜色,大小。这就意味着,商品类型的模型能够完成这种指定属性的过程——也就是,商品类型模型的实例化过程。
因此,现在已经可以看到商品类型的模型究竟是一个什么东西。但是,我们还有一个问题:不同商品类型有不同的属性,而我们无法穷举所有的属性。这么看起来,我们似乎无法把这个模型建立起来。
要解决在系统中建立商品类型模型的问题,我们还需要进行一次抽象。在这次抽象中,我们将某个属性看成是一个实例,而我们的抽象是要建立起来属性的模型。这体现的解决问题的思路就是:如果我无法穷举所有的东西,但是我能够穷举所有的生产这些东西的方法,那么我依然可以生产出任何我需要的东西。这有点类似于设计模式里面的建造者类型的设计模式,如工厂模式、抽象工厂模式。
现在是仔细观察属性的时候了。我的观察结果是,属性具备几个基本的特性:名字,描述,取值范围。其中描述甚至不是必须的,因为名字和描述无非是为了人类理解而做出的一种标记。我要重点讨论的是属性的取值范围。属性的取值可以分成两种,开放式取值和闭合式取值。所谓开放式取值,是指属性的值无法枚举出来,其可能性是无穷的;闭合式取值是,属性的值是从特定的某些值里面选取,这些特定的值是有穷的并且是可以被确定下来的。所以,要创建一个新的属性,无非就是指定属性的名字,指定名字的取值范围。(其实,属性还可以具备别的特性,不过这些特性更加多的是一种补充性质的,所以这里不加探讨)。对属性的特性进行分类,可以减少属性模型实例化的工作量。因为就计算机来说,常见的无非就是文本,字符串,数字,多选,单选,多媒体。
现在已经解决了属性无限性的问题,我们可以很方便的利用属性模型产生任何一种属性,无论是什么属性。而这些属性的不同组合方式可以产生各种商品类型。各种商品类型的实例化,最终就得出了无数的商品。用一幅图来描述:
在这里,商品类型模型就是一个属性集,该属性集用来描述所有的商品类型。
在真实的系统中,商品类型模型是找不到一个实体来对应它的,它实际上表现为一个创建属性以及给商品类型分配属性的模块。这样的一个系统大概会有几个组成部分:
属性录入部分。这个部分如果采用模板的方式的话,只需要准备几个模板便足够了。当然,如果不同的属性,属性的不太值之间有很强的依赖,那么这个部分就会变得比较复杂;
商品类型定义部分。这个部分无非就是一些属性的组合,复杂点的包括属性之间的约束,属性的现实取值等;
商品的录入。在商品类型定义的部分,定义好的商品类型,也就是商品模型,已经能够很明确的说明的一个商品是一个什么样的东西了。
这三个部分并不是一定要有准确的系统模块与之对应。实际上,简单起见的话,1和2是可以结合在一起。这种结合在一起的形式,还能避免一些“同样”的属性在不同的商品类型里面有不同的约束的问题。
**总结
**
除了上面举出来的例子,现实世界中还有很多可以应用的方面,尤其是在我们想要解决一些通用性的问题的时候。比如说审核。在一个互联网企业中,需要人工审核的内容有很多,其形式也是多样的。但是,依然可以抽象为类似于这种结构。每一类的审核内容,就对应于一个商品类型——一般也会被称为审核模板。比如说审核商品的信息,审核用户评论。而一个制造出这种模板的东西,就是审核模板模型,对应于商品类型模型。而这些模板依旧是由属性构成的,不同的构成方式决定了模板,构成模式一定时,属性的取值就是一个个最终的审核实例。
那么,一直抽象到属性的模型,是否就已经到达了抽象的终点?并不是这样的。在计算机领域内,二进制是抽象的终点。凡是计算机里面的东西,都是由二进制表示而成的,最终也将回归到这一点。