在使用一个类型的时候需要涉及到目标类型的实例化问题,在这里就闲侃一下。
有些讲述设计模式或者设计原则等内容的书籍上,建议我们:“将客户端和目标类型的实例化逻辑进行解耦”,这样客户端就不需要负责如何实例化的职责了,隐含的意思就是封装实例化的过程。这里的关键点是,如果实例化过程本身非常简单自然,例如一个简单的new调用,是不需要进行额外的技巧性封装的,也就更没有必要引入一个第三方的角色来承担实例化过程(例如工厂角色等)。
客户端两种获取实例的方式:
【不需要第三者引入】
既然要对实例化过程进行封装,并进而引入一个中间角色负责实例化的职责,那么如果实例化过程本身非常简单,干吗还需要引入一个第三方角色来负责实例化呢???
对于这种情况下,应该是蛮简单的,那就是通过构造函数或者静态方法接口获取实例。
1、普通构造函数。这是语言内置支持的,每个人应该都很熟悉了,就不罗唆说明了
2、静态接口获取实例的方式。遵照《重构与模式》一书中的说法,这种静态方法暂且成为“creation method”吧。引入这种方式一般有什么必须的理由呢:
1、构造函数的选择使用有一定的复杂度,例如构造函数过多、参数较多、构造函数本身有点难以理解(这往往是该类型代表的概念就有点难以理解^_^)等情况,针对一些常用的典型的场景提供几个静态获取实例的接口应该是对客户很有利的。例如你创建一个Color类型,提供了构造函数虽然并不复杂,就是RGB三种数值,那可能顺便提供几种便利的静态接口,例如提供系统的红、黄、蓝等颜色等。关于这种方式,有一个极大的负作用,那就是提供了非标准的创建实例的方式,这种方式并不能被继承等。
2、可能限制实例化过程,并且往往伴随着管理实例。例如相应的创建型如单件(singleton)、多件等等。这个大家应该也已经很熟悉了,就不说了^_^ 只是提醒一点,那就是要判断是否真的需要做这种限制,是否需要Class.newInstance的调用场景等。
3、通过静态接口提供子类型实例。这通常体现在返回的是本类型,但是真正的实现类型可能不是该类型的子类型,而又不想将改类型暴露给用户,希望用户同一使用该父类型进行操作。这种实现方式对外是自然的,也符合依赖倒置等原则;对内可能就是不自然的,毕竟是父类型知道了子类型的存在。
【引入第三者负责实例化职责】
引入的具体角色和意图的不同而不同,一般常用的如下:
1、实例化的过程本身并不会变化,在需要中这种创建过程就是具体的而不是一个变化的点。这种,一般引入一个静态工厂方法就可以了
2、如果实例化的过程变化,那就需要封装,暂且不考虑是何种变化。在面向对象设计中,一般遇到变化的点就是将其抽象封装,进而产生一个抽象概念,然后在应用上下文中以引用的方式来使用这个概念。那好了,如果要封装的是单一类型实例化过程的变化,那么就是常用的factory method;同理,如果需要面对的是创建系列类型实例化过程的变化,则就使用abstract factory(可以将其视为增强型的factory method^_^);如果这种变化不是正对类型,而是单纯针对实例化过程中步骤的,那么用builder来处理一下吧。
第三者的引入,自然会引入一定的复杂性,尤其是对于那些不熟悉设计模式的开发人员而言(例如,factory的引入必然会隐藏掉具体类型,这对那些不是很习惯面向抽象类型编程的开发者而言,很有可能就会觉得不自然^_^ )。还有的就是,不恰当的引入效果远不如不引入,引入之前一定要给自己一个充足的理由。 其实,这一点也同时适用于所有设计模式、设计技巧等的使用。
【总结】
总结起来就几个提问,对实例过程进行处理的时候需要问自己的问题:
1、是否需要为实例化过程引入第三者,引入的理由是什么?
2、如果不需要引入,需要对语言提供的构造函数特性进行进一步的技巧性处理?
3、如果需要引入第三者,针对需要引入的理由,这个第三者的角色又是怎样的?
本博客中的所有文章、随笔除了标题中含有引用或者转载字样的,其他均为原创。转载请注明出处,谢谢!