命名空间是什么
计算机科学领域中是通过名字来使用各种代码资源(变量和子程序)的,命名空间(namespace)则是组织这些资源的一组符号,例如目录树是就硬盘上文件们的命名空间。命名空间的设计目的是提供一种让一组名称与其他名称分隔开的方式。在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突。
如果你还是无法获得命名空间的概念,你只要想象给你一个1T的硬盘,但硬盘中无法创建文件夹,只能添加文件,你就能体会单一命名空间的坏处了,你必须保证1T的硬盘上所有文件的命名不能重复!这样你就能从日常操作文件夹的过程中抽象出命名空间这个概念了。
命名空间分类
我把当前不同语言中对命名空间的设计分为三类:单一命名空间、独立命令空间、目录树命名空间
首先我们知道,我们的代码都是由源文件组成的,而既然作为文件,那它们就处于某个文件系统中,而现在大部分的文件系统都采用了类似目录树的结构来组织文件的命名空间。
单一命名空间
虽然代码分布在不同的文件里,但是在运行时,所有的函数和类都会被加载到内存里,此时大家都在一个篮子里,没有不同文件不同文件夹的约束,如果此时每个类或每个函数仍旧使用它本身的名字,这就叫单一命名空间。
可以想象,你要面对跟在1T硬盘里无法建文件夹同样的问题。
你可能会说,这尼玛怎么写代码,好名字就那么多,取一个就少一个,哪来那么多名字给你取,何况自己取的名字之后都可能忘记,就别说要跟人合作的话,岂不是冲突得停不下来。
但其实不少语言都是这样的,比如C,比如Object-C(还莫名其妙地在IDE里给你建一个跟文件目录树不同的新目录结构),比如5.3之前的php,这种情况下的一种通用处理办法是:自制命名空间。怎么个自制法?就是在起名的时候在名字前加上前缀,完美。
目录树命名空间
单一命名空间明显是反人类的,需要设计有组织的命名空间。怎么设计呢?一个简单的思路是:既然代码由源文件组成,而源文件又被目录树组织,那命名空间能否直接使用目录树呢?我觉得可以,大家也觉得可以,于是就有了目录树命名空间。
目录树命名空间就是直接使用文件名作为代码资源最小单位的名字,每个文件夹作为不同的命名空间,使用文件夹路径区分不同的命名空间。
使用目录树作为命名空间有很多好处,比如:
- 优雅的一致性
- 使用起来非常直观,哪个命名空间下有哪些东西,打开文件夹就能看到,一目了然
- 由于文件系统保证了同一个文件空间下不会有文件重名,所以就等价于保证了同一个命名空间下不会有类重名,等价于保证了同名类一定有不同的命名空间,于是就保证了使用时一定有办法区分同名类
虽然目录树这么好,但还是有语言不完全按照目录树来走,甚至更有完全抛弃目录树作为命名空间的奇葩设计(其实也有其合理性啦):独立命名空间。
用Java举例,Java可以划归为「类目录树命名空间」,因为有两点不同
- 直接把目录树作为命名空间好像不太好实现,毕竟一个是文件系统中的东西,一个是运行环境中的东西,于是Java中还需要你在代码文件里显示地注明这个文件属于哪个命名空间(包名),但它又进行强制性地检查:你的命名空间注明得必须和文件夹路径一致!我心里不禁默默嘀咕这不是多此一举吗,不过还好现在的IDE在你建立文件的时候就会自动给你添加一条正确的命名空间
- Java中代码资源的最小单位可以说是类了,但Java语言允许一个文件中放多个类(虽然只能一个public的),虽然这并不是建议做法
独立命令空间
独立命名空间就是自己整一套跟目录树完全独立的命名空间,通常这个命名空间是用户自定义的,也就是由用户显示且自由地注明当前代码资源属于哪个命名空间,没有任何约束,PHP5.3之后就采用了这种做法。
这种方式初看会给人带来混淆,已经有一套由目录树构成的命名空间了,你再自己定义一套毫无关系的新的的命名空间,你不嫌累吗?你分得清吗?
当然这种做法会带来不直观的缺点,但同时也有其优点,比如在PHP的使用场景中,PHP作为脚本经常夹杂在各种资源文件中,如果完全使用目录树构成的命名空间,往往会造成空间的浪费,同时让PHP的结构变得非常松散,这就很适合由程序员自己定义一套独立的命名空间了。当然有的PHP框架会强制要求命名空间跟目录结构的一致性,这就是后话了。