使用 extends 关键字创建一个有问题的类,对于用户是一个很大的诱惑。
类的层级继承会造成很多有名的问题,包括 fragile base class(基础类会因为继承被破坏),gorilla banana problem(对象混杂着复杂的上下文环境),duplication by necessity(类在继承多样化时需要时时修改)等等。
虽然其他两种方法也有可能让你陷入这些问题,但是在使用 extend 关键字的时候,环境使然,就会把你引导上这条路。换句话说,他引导你向着一个不灵活的关系编写代码,而不是更有复用性的代码。
使用工厂函数的好处
工厂函数比起类和构造函数都更加的灵活,也不会把人引向错误的道路。也不会让你陷入深深的继承链中。你可以使用很多手段来模拟继承
1. 用任意的原型返回任意的对象
举个例子,你可以通过同一个实现来创建不同的实例,一个媒体播放器可以针对不同的媒体格式来创建实例,使用不同的API,或者一个事件库可以是针对DOM时间的或者ws事件。
工厂函数也可以通过执行上下文来实例化对象,可以从对象池中得到好处,也可以更加灵活的继承模型。
2. 没有复杂重构的担忧
你永远不会有把工厂函数转换成构造函数这样的需求,所以重构也没必要。
3. 没有 new
你不用new关键字来新建对象,自己可以掌握这个过程。
4. 标准的 this 行为
this 就是你熟悉的哪个this,你可以用它来获取父对象。举个例子来说,在 player.create() 中,this指向的是player,也可以通过call和apply来绑定其他this。
5. 没有 instanceof 的烦恼
6. 有些人喜欢直接不带new的写法的可读直观性。
工厂函数的坏处
- 并没有自动的处理原型,工厂函数原型不会波及原型链。
- this 并没有自动指向工厂函数里的新对象。
- 也许还会有一些很小的细节方面的差别,但是如果在开发过程中没有问题的话,也不用太担心。
结论
在我看来,类也许是一个方便的关键字,但是也不能掩饰他会把毫无防备的用户引向继承深坑。另一个风险在于未来的你想要使用工厂函数的可能性,你要做非常大的改变。
如果你是在一个比较大的团队协作里面,如果要修改一个公共的API,你可能干扰到你并不能接触到的代码,所以你不能对改装函数的影响视而不见。
工厂模式很棒的一个地方在于,他不仅仅更加强大,更加灵活,也可以鼓励整个队伍来让API更加简单,安全,轻便。
总结