对于工厂设计模式,其实应用十分广泛,尤其是在框架里面,例如Hibernate框架的SessionFactory创建session,还有Spring框架的javaBean的创建。因此对于设计模式的了解以及学习是十分有必要的。
首先,工厂模式可分为三种:简单工厂模式(也称静态工厂模式)、工厂方法模式、抽象工厂模式。工厂模式,顾名思义,工厂就是用来创建产品的,那么在我们的java里就是用来创建对象的。接下来逐一来看看它们是怎么实现的。
简单工厂模式:
例如现在我需要创建一部手机,但手机有品牌之分,例如小米和苹果,不同品牌的手机肯定需要创建不同的手机,因此在这里涉及类手机(Phone)、小米手机(XiaoMi)和苹果手机(IPhone)三个类,让XiaoMi类和IPhone类继承Phone。然后创建一个工厂类PhoneFactory。在PhoneFactory方法里提供一个方法用来创建并返回不同品牌的手机。具体的代码如下:
package com.tiantang.factory.simpleFactory;
public class Phone {
public Phone(String brand){
this.brand=brand;
}
public Phone(){}
protected String brand;
}
package com.tiantang.factory.simpleFactory;
public class IPhone extends Phone{
public IPhone(String brand) {
super(brand);
}
}
package com.tiantang.factory.simpleFactory;
public class XiaoMi extends Phone{
public XiaoMi(String brand) {
super(brand);
}
}
package com.tiantang.factory.simpleFactory;
/**
* 简单工厂模式
* 缺点:当增加一个新的手机工厂时,需要修改工厂类的源代码
* 优点:代码简单
* @author LiuJinkun
*
*/
public class PhoneFactory {
public static Phone createPhone(String brand){
if("苹果".equals(brand)){
return new IPhone(brand);
}else if("小米".equals(brand)){
return new XiaoMi(brand);
}else{
return null;
}
}
}
当需要一个Phone对象时,我们只需要通过向PhoneFactory的createPhone的方法传递一个具体的手机品牌参数即可: package com.tiantang.factory.simpleFactory;
public class Client {
public static void main(String[] args) {
Phone phone=PhoneFactory.createPhone("苹果");
System.out.println(phone.brand);
Phone phone2=PhoneFactory.createPhone("小米");
System.out.println(phone2.brand);
}
}
这样我们就实现了简单工厂模式,看看简单工厂模式的UML图:
使用了简单工厂模式之后在外部我们就只需要和PhoneFactory和Phone打交道了,而不必和每一个具体的对象关联了。然而简单工厂模式的缺点也比较明显,例如,现在又需要一部华为手机,怎么办呢?我们岂不是要修改PhoneFactory类的源代码,在createPhone()方法里增加一个else if,这显然违背了面向对象设计时的开闭原则(OCP)。但简单工厂模式的最大优点在于设计起来简单,代码量少,也比较好理解,容易看懂,一般我们在使用时可以使用这种设计模式。
工厂方法模式:
工厂方法模式的UML图如下:
通过图可以看到,定义了一个Factory接口,接口中有一个方法create(),同时提供了该接口的两个实现类(XiaoMiFactory类生产小米手机,IPhoneFactory类生产苹果手机),在实现类中实现了create()方法的具体实现。这样在外部我们要得到那个品牌的手机就只需要通过相应的工厂就可以创建了,具体的代码如下:
package com.tiantang.factory.factoryMethod;
/**
* 测试工厂方法模式
* 缺点:当增加一个新的品牌的品牌的手机时,需要增加的类太多
* 优点:不需要修改原有工厂类的源代码
* @author LiuJinkun
*
*/
public interface Factory {
Phone create();
}
package com.tiantang.factory.factoryMethod;
public class IPhoneFactory implements Factory {
@Override
public Phone create() {
return new IPhone("苹果手机");
}
}
package com.tiantang.factory.factoryMethod;
public class XiaoMiFactory implements Factory {
@Override
public Phone create() {
return new XiaoMi("小米手机");
}
}
package com.tiantang.factory.factoryMethod;
public class Client {
public static void main(String[] args) {
Phone phone=new IPhoneFactory().create();
Phone phone2=new XiaoMiFactory().create();
System.out.println(phone.brand);
System.out.println(phone2.brand);
}
}
当新增需求时,如果有新品牌的手机需要,则只需要新增加一个Factory接口的实现类和Phone的子类即可,不需要修改Factory的源代码,这样满足了面向对象的OCP原则。但同时也会出现一个问题,随着手机品牌的增加,每新增一个品牌的手机,我们就需要增加两个类,当品牌越来越多时,我们的类也就越来越多,这样就会造成我们的项目看起来不是那么的美观。至于简单工厂模式和工厂方法模式究竟应该选择哪一种,读者可根据自己的需求来选择,能将碰到的问题解决,选择哪种模式都可以。 抽象工厂模式:
抽象工厂模式一般针对产品族而言,例如我们可能碰到这样的情形:汽车有高端车和低端车之分,而组成零件轮子,座椅,发动机也有高端和低端之分,这样想要创建高端和低端汽车就需要两个工厂,而对于这两种车它们的就够都一样,都需要轮子,座椅,发动机,因此这两个工厂的行为都是一样的(制造轮子,座椅,发动机),不一样是它们的等级不同。因此就用了产品族的概念。如下用代码来实现这种情形:
先看看抽象工厂模式的UML图:
具体的代码如下:
package com.tiantang.factory.abstractFactory;
/**
* 汽车引擎
* @author LiuJinkun
*
*/
public interface Engine {
void start();
}
/**
* 高端引擎
* @author LiuJinkun
*
*/
class LuxuryEngine implements Engine{
@Override
public void start() {
System.out.println("启动快");
}
}
/**
* 低端引擎
* @author LiuJinkun
*
*/
class LowEngine implements Engine{
@Override
public void start() {
System.out.println("启动慢");
}
}
package com.tiantang.factory.abstractFactory;
/**
* 汽车轮胎
* @author LiuJinkun
*
*/
public interface Tyre {
void run();
}
/**
* 高端轮胎
* @author LiuJinkun
*
*/
class LuxuryTyre implements Tyre{
@Override
public void run() {
System.out.println("使用寿命长");
}
}
class LowTyre implements Tyre{
@Override
public void run() {
System.out.println("使用寿命短");
}
}
package com.tiantang.factory.abstractFactory;
/**
* 汽车座椅
* @author LiuJinkun
*
*/
public interface Seat {
void quality();
}
/**
* 高端座椅
* @author LiuJinkun
*
*/
class LuxurySeat implements Seat{
@Override
public void quality() {
System.out.println("坐起来非常舒服");
}
}
/**
* 低端座椅
* @author LiuJinkun
*
*/
class LowSeat implements Seat{
@Override
public void quality() {
System.out.println("坐起来不是特别舒服");
}
}
package com.tiantang.factory.abstractFactory;
/**
* 生产汽车零件的工厂
* @author LiuJinkun
*
*/
public interface CarFactory {
/**
* 生产汽车引擎
* @return
*/
Engine createEngine();
/**
* 生产汽车座椅
* @return
*/
Seat createSeat();
/**
* 生产汽车轮胎
* @return
*/
Tyre createTyre();
}
package com.tiantang.factory.abstractFactory;
/**
* 生产低端汽车零件的工厂
* @author LiuJinkun
*
*/
public class LowCarFactory implements CarFactory{
@Override
public Engine createEngine() {
return new LowEngine();
}
@Override
public Seat createSeat() {
return new LowSeat();
}
@Override
public Tyre createTyre() {
return new LowTyre();
}
}
package com.tiantang.factory.abstractFactory;
/**
* 生产高端汽车零件的工厂
* @author LiuJinkun
*
*/
public class LuxuryCarFactory implements CarFactory{
@Override
public Engine createEngine() {
return new LuxuryEngine();
}
@Override
public Seat createSeat() {
return new LuxurySeat();
}
@Override
public Tyre createTyre() {
return new LuxuryTyre();
}
}
package com.tiantang.factory.abstractFactory;
/**
* 测试代码
* @author LiuJinkun
*
*/
public class Client {
public static void main(String[] args) {
CarFactory luxuryFactory=new LuxuryCarFactory();
CarFactory lowFactory=new LowCarFactory();
Engine engine=luxuryFactory.createEngine();//高端工厂创建的引擎是高端引擎
engine.start();
engine=lowFactory.createEngine();//低端工厂创建的是低端引擎
engine.start();
}
}
从代码中就可以看到,抽象工厂模式比较复杂,实现起来相对比较麻烦,而且如果碰到产品族中新增一种车:中端车,这时候想要扩展代码就比较麻烦了,因此,抽象工厂模式的扩展性比较麻烦,目前笔者在学习过程中很少碰到抽象工厂模式,也没使用过抽象工厂模式,因此,对于抽象工厂模式的理解比较浅显,如果读者想要了解得更深入的话,可以自行查阅相关书籍。 最后总结一下,其实这三种抽象模式最终的目的就是为了降低类之间的耦合性,尤其是当从外部访问时,都是为了尽可能的减少类与类的依赖关系,具体应该使用哪一种工厂模式,读者应该在达到自己的目的的同时,那种方便就使用哪一种。