4.2 升级为多个工厂类
当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰
例如,一个产品类有5个具体实现,每个实现类的初始化(不仅仅是new,初始化包括new一个对象,并对对象设置一定的初始值)方法都不相同,如果写在一个工厂方法中,势必会导致该方法巨大无比,那该怎么办?
考虑到需要结构清晰,我们就为每个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联
我们还是以女娲造人为例,每个人种都有一个固定的八卦炉,分别造出黑色人种、白色人种、黄色人种
每个人种(具体的产品类)都对应了一个创建者,每个创建者都独立负责创建对应的产品对象,非常符合单一职责原则,看看代码变化
- 抽象方法中已经不再需要传递相关参数了,因为每一个具体的工厂都已经非常明确自己的职责:创建自己负责的产品类对象。
- 黑色人种的创建工厂实现
- 黄色人种的创建类
- 白色人种的创建类
- 三个具体的创建工厂都非常简单,但是,如果一个系统比较复杂时工厂类也会相应地变复杂。
- 场景类NvWa修改后的代码
- 运行结果还是相同
每一个产品类都对应了一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响。为什么这么说呢?如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。因为工厂类和产品类的数量相同,维护时需要考虑两个对象之间的关系。
当然,在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。
4.3 替代单例模式
单例模式的核心要求就是在内存中只有一个对象
,通过工厂方法模式也能只在内存中生产一个对象。
- 工厂方法模式替代单例模式类图
- Singleton定义了一个private的无参构造函数,目的是不允许通过new的方式创建一个对象
- 单例类
- Singleton保证不能通过正常的渠道建立一个对象
那SingletonFactory如何建立一个单例对象呢?
反射!
- 负责生成单例的工厂类
- 通过获得类构造器,然后设置private访问权限,生成一个对象,然后提供外部访问,保证内存中的对象唯一。
以上通过工厂方法模式创建了一个单例对象,该框架可以继续扩展,在一个项目中可以产生一个单例构造器,所有需要产生单例的类都遵循一定的规则(构造方法是private),然后通过扩展该框架,只要输入一个类型就可以获得唯一的一个实例。
3.4 延迟初始化(Lazy initialization)
一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用
延迟初始化是工厂方法模式的一个扩展应用
- 延迟初始化的通用类图
- ProductFactory负责产品类对象的创建工作,并且通过prMap变量产生一个缓存,对需要再次被重用的对象保留
- 延迟加载的工厂类
- 通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。
延迟加载框架是可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现,这样的处理是非常有意义的,例如JDBC连接数据库,都会要求设置一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。
延迟加载还可以用在对象初始化比较复杂的情况下,例如硬件访问,涉及多方面的交互,则可以通过延迟加载降低对象的产生和销毁带来的复杂性。