五、两种重要的数据容器(三)
-
前言
数据容器就是装载各种容器的数据结构,比较实用的两种:数组和容器。
数组
两大特点:
- 每个数组都有一组从0开始的下标,可以有着快速定位的能力
- 排序和数组有密切的关系,数组的快速定位能力,能帮助很多其他数据结构来优化排序效率
散列表
散列表本质上就是一个由链表组成的数组。通过散列算法,使它同时具备散列表和数组的优点:既能像链表那样高速地增加和删除元素,也几乎能和数组一样快速定位元素。
散列表像银行的保险柜,每一个柜子对应一把唯一的钥匙,虽然柜子集中存放,但相互隔离,彼此保密。
重要应用——实现Container
实例背景:一个工程越写越大,越来越多的service这种中间层的类需要单例模式。这样会有以下两个问题:
- 大量重复的单例代码
- 代码由多人所写,写到后来,有的不需要写成单例的也被照搬成了单例。
分析:需要一个统一的方法来管理这些类。可以用Container。
Container的核心是散列表。首先,Container可以用字典实现:
Dictionary<string,object> container = Dictionary<string,object>();
之后,在字典里添加所有的单例,它的key值是string类型,代表要实现的单例的类名。
container.Add("ConfigService",new ConfigService());
为了方便管理,我们把所有的key综合到某个class里或者枚举类型里。
class ServiceKeys{ public static readonly string ConfigService = "ConfigService "; public static readonly string DatabaseService = "DatabaseService "; }
然后取对象
ConfigService configService = container[ServiceKeys.ConfigServices]; //别忘了的添加语句也替换 Container.Add(ServiceKeys.ConfigService , new ConfigService());
保证单例,我们只需要把container自己定义为单例就可以了。一旦container变成了单例,那么它的子元素自然是唯一的。
但新的问题出现了:非单例的service怎么办?因为有的service不需要单例;我想所有的对象都从统一的接口取。
~~~~~~~
这样做的好处:
- 类里面的单例代码都去掉了,减少了大量重复函数
- 由Container统一管理创建对象
- 有利于单元测试,所有的数据流都经过了Container这个点集中式管理
- 散列表的特性决定了数据集中却不耦合
Container和工厂模式类比,区别如下:
- 解决的问题不一样。Container为了解决无数点对点之间的杂乱的连线,将它们剪断并统一管理。工厂模式主要是封装创建对象的负责逻辑,以提高代码的抽象等级。
- 获得的对象从属关系不一样。从Container里获得的对象,和Container是有所属关系的,属于Container。而一旦对象从工厂创建出来,和工厂再也没有关系。
控制发转
字面意思:“某种权利交给了别人,于是被反转了”。
实现的两种方式:
- 依赖查找,类似上述的Serice Locator。“你创建对象的权利转移给了Container”,被“反转”了。
- 依赖注入,通过属性注入。