场景引入
假如要设计一个汽车保险管理程序。汽车保险分为很多险种,例如人身伤亡(Body Injur)、碰撞(Collision)、驾驶员本身伤亡(Person Injur)、财产损失(Property)、综合险(Com)等。如果一个应用知道它所需要的准确功能,它可以从客户类的主方法中直接初始化类结构体中的某个子类,并且调用该类提供的功能。
不使用工厂模式
假设我们现在要初始化 BodyInjur 类,其 UML 图和步骤如下
步骤一:定义产品类接口 Autolnsurancel
public interface Autolnsurancel{
abstract String getlnsurlnfo(); // 抽象方法
}
步骤二:创建产品子类(以 Bodylnjur 为例)
public class Bodylnjur implements Autolnsurance{
private String description;
public String getlnsurlnfo(){
System.out.println(description)
}
}
步骤三:创建客户端
public class ClientGUI{
public static void main(String[] args) {
Bodylnjur创建过程的其它代码
Autolnsurance a = new Bodylnjur ();
a.getlnsurlnfo();
}
分析
这种设计有以下几种不足
- 可扩展性和可维护性差。如果要改变类创建过程的其它代码,则需要重新编译整个ClientGUI类
- main()集中了 Bodylnjur 类创建过程的其它代码,程序可读性差
不使用工厂模式,进行简单封装
为了改善不足②,我们可以将创建类的对象的责任封装在一个单独的方法中,使用createObj() 方法克服了在main()方法中的混乱情况。
步骤一:定义产品类接口 Autolnsurancel
public interface Autolnsurancel{
abstract String getlnsurlnfo();
}
步骤二:创建产品子类(以 Bodylnjur 为例)
public class Bodylnjur implements Autolnsurance{
private String description;
public String getlnsurlnfo(){
System.out.println(description)
}
}
步骤三:创建客户端
public class ClientGUI{
public static void main(String[] args) {
Autolnsurance a = this.createObj();
a.getlnsurlnfo();
}
}
public void createObj(){
Bodylnjur创建过程的其它代码
Autolnsurance a = new Bodylnjur ();
return a;
}
分析
与设计1相比,设计2将 main() 方法中创建对象的过程转移到了 createObj() ,但仍存在以下的问题
- 可扩展性和可维护性差。如果要改变类创建过程的其它代码,则需要重新编译整个ClientGUI类
简单工厂模式
为了改善不足①,我们可以将以上创建对象的过程从 ClientGUl 类中分离出来,由另一个类来封装对象的创建工作。该设计将类的选择和对象的创建封装在一个方法(即工厂方法)getInsurObj 中,而将这个方法封装在一个独立的类(即工厂类)PolicyProducer里面。
步骤一:定义产品类接口 Autolnsurancel
public interface Autolnsurancel{
abstract String getlnsurlnfo();
}
步骤二:创建产品子类(以 Bodylnjur 为例)
public class Bodylnjur implements Autolnsurance{
private String description;
public String getlnsurlnfo(){
System.out.println(description)
}
}
步骤三:创建工厂类
public class PolicyProducer{
public static Autolnsurance getPolicyObj(String option){
Autolnsurance policy=null;
if(option. compareTo("bodylnjure")==0){
bodylnjur创建过程的其它代码
policy=new Bodylnjur();
}
else if(option. compareTo("collision")==0){
collision创建过程的其它代码
poliy=new Collision();
}
else if(option. compareTo("com")==0){
com创建过程的其它代码
policy=new Comprehensive();
}
else if(option. compareTo("personlnjure")==0){
personlnjure创建过程的其它代码
policy=new Personlnjur();
}
return policy;
}
}
步骤四:创建客户端
public class ClientGUI{
public static void main(String[] args) {
Stirng option="bodylnjure";
Autolnsurance a = PolicyProducer.getPolicyObj(option);
a.getlnsurlnfo();
}
}
分析
与设计2相比,设计3将创建对象的过程转移到了工厂类 PolicyProducer 的工厂方法 getInsurObj 中,但仍存在以下的不足
- 改善了可维护性和可扩展性。但如果要添加或者改变一些选择条件,仍需要重新编译整个PolicyProducer 工厂类,不符合开闭原则
描述
简单工厂模式是由一个工厂对象根据收到的消息决定要创建哪一个类的对象实例,被创建的实例通常都具有共同的父类.
使用场景
工厂类负责创建的对象比较少,客户只需要传入工厂类参数,对于如何创建对象(逻辑)不关心。简单工厂模式很容易违反高内聚低耦合的原则,因此一般只在很简单的情况下使用。
工厂模式
为了改善不足①,我们可以将简单工厂模式中单一的工厂类 PolicyProdecer 改写为一个层次类
步骤一:定义产品类接口 Autolnsurancel
public interface Autolnsurancel{
abstract public String getlnsurlnfo();
}
步骤二:创建产品子类(以 Bodylnjur 为例)
public class Bodylnjur implements Autolnsurance{
private String description;
public String getlnsurlnfo(){
System.out.println(description)
}
}
步骤三:定义工厂类接口 PolicyProducer
public class PolicyProducer{
abstract public String getlnsurObj();
}
步骤四:创建工厂子类(以 Bodylnjur 为例)
public class BodyPolicy implements PolicyProducer{
public Autolnsurance getlnsurObj(){
bodylnjur创建过程的其它代码
return new Bodylnjur();
}
}
步骤五:创建客户端
public class ClientGUI{
public static void main(String[] args) {
PolicyProducer pp = new BodyPolicy();
Autolnsurance a=pp.getlnsurObj(); // 多态复用
a.getlnsurlnfo();
}
}
分析
与设计3相比,设计4有以下优点
- 增加新产品,只需要在Product类的结构体中增加一个实类,并且在工厂类层次结构体中增加一个相应的能产生该新产品类对象的实类。这种模式不需要修改客户类 (如 ClientGUI),无需修改或者重新编译抽象的工厂方法类与已经存在的具体工厂方法类,符合了开闭原则。
描述
定义一个创建对象的工厂接口,让子类决定实例化哪一个类,将实际创建工作推迟到子类当中。
使用场景
工厂类负责创建的对象比较少,但只有一个产品族(如示例中的 PolicyProducer)