《Java设计模式及实践》—2.2 工厂模式
2.2 工厂模式
正如前面章节所描述,在面向对象编程中,继承是一个基本概念,它与多态共同构成了类的父子继承关系(Is-A关系)。Car对象可以被当作Vehicle对象处理,Truck对象也可以被当作Vehicle对象处理。一方面,这种抽象方式使得同一段代码能为Car和Truck对象提供同样的处理操作,使代码更加简洁;另一方面,如果要扩展新的Vehicle对象类型,比如Bike或Van,不再需要修改代码,只需添加新的类即可。
在大多数情况下,最棘手的问题往往是对象的创建。在面向对象编程中,每个对象都使用特定类的构造器进行实例化操作,如下面代码所示:
这段代码说明了Vehicle和Car两个类之间的依赖关系。这样的依赖关系使代码紧密耦合,在不更改的情况下很难扩展。举例来说,假设要用Truck替换Car,就需要修改相应的代码:
这里存在两个问题:其一,类应该保持对扩展的开放和对修改的关闭(开闭原则);其二,每个类应该只有一个发生变化的原因(单一职责原则)。每增加新的类造成主要代码修改时会打破开闭原则,而主类除了其固有功能之外还负责实例化vehicle对象,这种行为将会打破单一职责原则。
在这种情况下就需要一种更好的设计方案。我们可以增加一个新类来负责实例化vehicle对象,称之为简单工厂模式。
2.2.1 简单工厂模式
工厂模式用于实现逻辑的封装,并通过公共的接口提供对象的实例化服务,在添加新的类时只需要做少量的修改。
简单工厂的实现描述如图2-2所示。
类SimpleFactory中包含实例化ConcreteProduct 1和ConcreteProduct 2的代码。当
客户需要对象时,调用SimpleFactory的createProduct()方法,并提供参数指明所需对象的类型。SimpleFactory实例化相应的具体产品并返回,返回的产品对象被转换为基类类型。因此,无论是ConcreteProduct 1还是ConcreteProduct 2,客户能以相同的方式处理。
图 2-2
1.静态工厂模式
下面我们写一个简单的工厂类用来创建Vehicle实例。我们创建一个抽象Vehicle类和继承自它的三个具体类:Bike、Car和Truck。工厂类(也叫静态工厂类)代码如下所示:
工厂类逻辑非常简单,只负责Vehicle类的实例化,符合单一职责原则;用户只调用Vehicle接口,这样做可以减少耦合,符合依赖倒置原则;但是当增加一个新的Vehicle类时,需要对VehicleFactory类进行修改,这样就打破了开闭原则。
我们可以改进这种简单工厂模式,使得注册的新类在使用时才被实例化,从而保证其对扩展开放,同时对修改闭合。
具体的实现方式有以下两种:
使用反射机制注册产品类对象和实例化。
注册产品对象并向每个产品添加newInstance方法,该方法返回与自身类型相同的新实例。
2.使用反射机制进行类注册的简单工厂模式
为此,我们需要使用map对象来保存产品ID及其对应的类:
然后,增加一个注册新Vehicle类的方法:
构造方法如下所示:
但在某些情况下,反射机制并不适用。比如,反射机制需要运行时权限,这在某些特定环境中是无法实现的。反射机制也会降低程序的运行效率,在对性能要求很高的场景下应该避免使用这种机制。
3.使用newInstance方法进行类注册的简单工厂模式
前面的代码中使用了反射机制来实现新Vehicle类的实例化。如果要避免使用反射机制,可以使用注册新Vehicle类的类似工厂类,不再将类添加到map对象中,而是将要注册的每种对象实例添加其中。每个产品类都能够创建自己的实例。
首先在Vehicle基类中添加一个抽象方法:
对于每种产品,基类中声明为抽象的方法都要实现:
在工厂类中,更改map用于保存对象的ID及其对应的Vehicle对象:
通过实例注册一种新的Vehicle类型:
也要相应地改变createVehicle方法:
- 点赞
- 收藏
- 关注作者
评论(0)