理财产品的创建
开篇先介绍一下我们公司的业务,我们公司是一家金融理财公司。在公司的业务中有很多打包好的理财产品,种类繁多。它们既有很多相似的特征,也有一些区别。不久前,公司的ceo觉得我们的这些理财产品的名称,以及里面包含的专业术语,对于普通的用户理解起来有很大的困难。于是乎,需求出来了,将所有之前的理财产品名称和一些描述,全部换掉。使用一些让用户户更容易理解的名称和描述。但是为了兼容旧的产品种类,我们不能在旧的种类上直接修改,需要将之前的种类,一对一的再新生成一套。面对这样的需求,就要用到我们介绍的工厂模式。
那我们的系统是怎么设计的呢?我们使用了工厂方法模式(factory method pattern),先看看我们的类图。
类图比较简单, AbsFinancialFactory是一个抽象类,定义了一个产生金融产品的工厂类,FinancialFactory为实现类,完成具体的任务-生成新的理财产品。FinancialProduct是我们的产品抽象类,定义了一些金融产品的共有属性和方法。ImproveSalaryProduct和NewUserFinancialProdcut是我公司旗下的两个具体的理财产品”旺薪宝”和”新手包”。Client则是场景类。
下面我们具体看看代码:
AbsFinancialFactory.java
1 |
|
AbsFinancialFactory是抽象工厂类,定义了创建产品的方法createProduct(Class
FinancialFactory.java
1 |
|
FinancialFactory是具体的实现类,这里使用了java的反射去创建具体的产品实例。
FinancialProduct.java
1 |
|
FinancialProduct是抽象的产品类,定义了我们平台产品的一些共同属性和方法。
NewUserFinancialProduct.java
1 |
|
NewUserFinancialProduct是具体的金融产品类”新手宝“
ImproveSalaryProduct.java
1 |
|
ImproveSalaryProduct是具体的金融产品类”旺薪宝”
现在需要看看我们的场景类Client,怎么通过工厂去创建具体的金融产品的。直接上代码:
1 |
|
输出结果:
1 |
|
通过结果了解到我们的产品已经成功的生产出来了。
工厂方法模式的定义
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。
工厂方法的通用类图:
在工厂方法模式中,抽象产品类Product负责定义产品的共性,实现事物最抽象的定义。Factory为抽象创建类,具体的实现在ConcreteFactory中完成。工厂方法的模式变种很多。我们来看个比较实用的通用代码。
抽象产品类
1 |
|
具体产品类,可能有多个。
1 |
|
1 |
|
抽象工厂类
1 |
|
具体工厂类
1 |
|
场景类
1 |
|
该通用代码是一个比较实用、易扩展的框架,当然也可以自行的进行扩展。
工厂方法模式的应用
工厂方法模式的优点
首先,良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的过程,降低模块之间的耦合。
其次,工厂模式的扩展性非常的好。比如上面的理财产品,我们想再增加一个,只需要新建个具体的产品类就可以了。工厂类不需要任何的修改。
再次,屏蔽产品类。我们不需要关心产品类里的具体实现,只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不会方式变化。
工厂方法模式的缺点
首先,新加产品时需要添加具体的产品类,有时还需要添加具体的工厂类,系统中的类成对增长,增加了系统的复杂性。
其次,为了扩展性,定义了抽象层,增加了系统的理解难度.
工厂方法模式的扩展
工厂方法模式有很多的扩展,下面介绍几种常用到的扩展。
- 简化为简单工厂模式
如果一个模块仅需要一个工程类的时候,就没必要把它生产出来,使用静态方法就可以了。根据这个要求,我们可以修改上面的例子为简单工厂模式,将AbsFinancialFactory去掉,修改一下FinancialFactory,类图如下
FinancialProduct类修改为:
1 |
|
场景类
1 |
|
运行结果:
1 |
|
我们将之前的工厂方法模式简化成简单工厂模式,代码只需要两个地方发生变化。使的系统变的简单。但是它有个缺点就是工厂类不容易扩展了。
- 升级为多个工厂类
当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。
考虑到需要清晰,我们就为每个产品定义一个工厂类。具体的类图如下:
每个产品都对应了一个工厂,每个工厂都独立负责创建对应的产品,非常的符合单一责任原则。按照这种模式我们看看代码发生了哪些变化
抽象工厂类
1 |
|
抽象工厂中的创建方法不再需要传递参数,因为具体的工厂只生产对应的产品。
”新手宝”的工厂
1 |
|
“旺薪宝”的工厂
1 |
|
场景类
1 |
|
运行接口还和前面的一样。
我们回头看一下,每一个产品对应一个工厂,好处是创建的职责单一,代码清晰,但是不好的地方是使扩展变的麻烦,每增加一个产品类需要对应的生成一个工厂类,同时还的维护两个类之间的关系。
当然,在复制的应用中一般都使用多工厂的方法,然后增加一个协调类,避免调用者与各个子工厂交流。,协调类的作用是封装子工厂类,对高层模块暴露统一的接口。
- 替代单例模式
单例模式其实就是内存中只存在一个对象,通过工厂方法模式也可以达到相同的目的。类图如下:
Singleton定义了一个private的无参构造函数。目的是不允许new对象。
1 |
|
Singleton不能通过new来创建一个对象,那么SingletonFactory怎么创建Singleton的对象呢,答案是反射。
1 |
|
这样只要在团队内约定好,只能通过SingletonFactory去创建Singleton对象,而不允许其他人在其他类中使用反射获取Singleton的对象,我们就能保证Singleton的实例是唯一的。
现在,在场景类中测试一下最后的结果
1 |
|
运行结果显示,我么获得确实是单例
1 |
|
总结
工厂方法模式适用情况包括:一个类不知道它所需要的对象的类;一个类通过其子类来指定创建哪个对象;将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。