在第一次用LinkedHashSet带来的思考(一)
中,顺着
LinkedHashSet的保序功能是怎么实现这一问题看了HashSet源码, 注意到HashSet的一个构造方法前没有写访问修饰符,
这样也就只有跟HashSet在同一个包的类才能访问这个构造方法了.
为了下面的谈论方便,我们将这种没写访问修饰符的情况称为"包修饰符",当然也有叫"默认修饰符"的,但个人觉得还是这个"包修饰符"较好些,
可以从名字上看出它的作用来.
突然间觉得这种处理很巧妙: 原来在HashSet里边深藏着一个LinkedHashSet!真是藏在深闺无人知呀!在这个"包修饰符"修饰的构造方法的帮助下, LinkedHashSet的实现就显得很干净简洁了.
但不免会想, 有没有必要把LinkedHashSet的功能实现放到父类呢? 在自身类里不行吗? 若在自身类里,
别的类如想有同样的功能而简单地copy/paste也不想用"hasA"的组合方式的话, 就只能继承LinkedHashSet, 那样继承太深,
写在HashSet类里, 继承层次上会少些. 这样解释对不? 看来这OO设计中,在处理继承上有很多考虑的地方,
而平时做项目的工作中也很少体会到.
上面是很干瘪地写了些关于HashSet里那个"包修饰符"构造方法的思考,
写的很难受, 根本原因是自己对这个的理解不对位,也就没能剥茧抽丝地把这个概念下的东西说清楚.
下面我试着描述下LinkedHashSet实现过程中所体现的"HasA"的组合方式.
我们知道除copy/paste外, 正规军里的做法有继承和组合, 也就是"isA"和"hasA". 不过在设计实践中, 有这样的说法, 若只是为了代码重用的话, 尽量地用hasA的组合的方式. 一般而言, 在选择isA还是hasA时, 有如下参考:
1, 不要仅仅为了代码重用而用isA的继承, 而用hasA的组合方式重用代码. 若用isA的继承, 当父类有什么改变时,子类就受到很大的牵连.
2, 不要仅仅为了多态而用isA的继承,而用接口加组合方式.
现在结合HashSet的实现, 看这两点的应用.HashSet内部用一个HashMap来作为数据的最终存放地, 它并没有继承HashMap类. 从另一方面来说, 为了实现多态, HashSet实现了Set接口.
见的很糟, 比自己的预期差不少. .....