【Java 设计模式 · 创建型】工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)


建议使用JDK版本:JDK 1.9+

创建型模式:关注对象的创建过程,它描述如何将对象的创建、使用分离,让用户无需关心对象的创建细节,从而降低系统的耦合度,让设计方案易于修改、扩展。

一、简单工厂模式

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。

这种模式出现在很多框架中,比如 MyBatis 的 SqlSessionFactory 类,此外Spring 中也大量应用工厂模式。

1、结构

  • Factory(工厂角色):
    工厂类,负责实现创建所有产品实例的内部逻辑,可以被外界直接调用以创建所需对象产品。
  • Product(抽象产品角色):
    工厂类创建对象的父类,封装了各种产品对象的公用方法,使得创建所有的具体产品都是其子类对象,只需定义一个工厂。
  • ConcreteProduct(具体产品角色):
    简单工厂模式的创建目标,继承自抽象产品角色,需声明抽象产品中的抽象方法。

简单工厂模式

2、举例

实现

样品代码:
Car抽象类(抽象产品类,定义产品)

public abstract class Car {
    //为更好的演示,我们不定义属性
    //定义方法run()
    public abstract void run();
}

SUV类(具体产品类,继承自Car类)

public class SUV extends Car{
    //重写父类方法
    @Override
    public void run() {
        System.out.println("SUV跑起来");
    }
}

Hatchback类(具体产品类,继承自Car类)

public class Hatchback extends Car{
    //重写父类方法
    @Override
    public void run() {
        System.out.println("小轿车跑起来");
    }
}

CarFactory类(工厂类):

public class CarFactory {
    public static Car createCar(String carType) {
        //定义引用
        Car car = null;
        try {
            //反射获取Class对象(包名 + 类名)
            Class clazz = Class.forName("com.simple." + carType);
            //获取实例(JDK 1.9推荐使用,可以根据参数不同,调用不同的构造方法)
            car = (Car) clazz.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            //不存在这个类
            System.out.println("没有这款车!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回引用指向的实例
        return car;
    }
}

测试代码:

//用户无需关心内部实现,只需知道类型名称即可
//SUV
Car car1 = CarFactory.createCar("SUV");
car1.run();
//Hatchback
Car car2 =  CarFactory.createCar("Hatchback");
car2.run();

运行结果:
运行结果

3、优点

  • 客户无需决定何时创建对象,仅仅使用产品,实现了创建、使用的分离。
  • 客户无需知道所创建的具体对象类名,只需要知道具体产品类所对应的参数即可。
  • 通过引入配置文件,可一定程度上提高系统的灵活性。

4、缺点

  • 工厂类集中了所有创建逻辑,职责过重。
  • 系统扩展困难,一旦添加新的产品,则必须修改工厂逻辑,不易于维护。
  • 简单工厂模式使用了静态工厂方法,无法形成基于继承的等级结构。

二、工厂方法模式

工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。

1、结构

  • Product(抽象产品):
    定义产品的接口,工厂方法模式创建对象的超类型,也就是产品对象的公共父类。
  • ConcreteProduct(具体产品):
    实现了接口产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
  • Factory(抽象工厂):
    在抽象工厂类中声明了工厂方法(Factory Method),用于返回一个产品。所有创建对象的工厂类必须实现此接口。
  • ConcreteFactory(具体工厂):
    抽象工厂类和子类,实现了在抽象工厂中声明的工厂方法,并可由客户端调用,返回一个具体产品类的实例。

工厂方法模式

2、举例

实现

样品代码:
Car接口

public interface Car {
    //Car接口,定义方法
    void run();
}

SUV类

public class SUV implements Car{
    //重写父类方法
    @Override
    public void run() {
        System.out.println("SUV跑起来");
    }
}

Hatchback类

public class Hatchback implements Car {
    //重写父类方法
    @Override
    public void run() {
        System.out.println("小轿车跑起来");
    }
}

CarFactory接口

public interface CarFactory {
    //定义创造汽车方法
    Car createCar();
}

SUVFactory类

public class SUVFactory implements CarFactory {
    //方法的具体实现
    @Override
    public Car createCar() {
        //定义引用
        SUV suv = null;
        try {
            //反射获取Class对象(包名 + 类名)
            Class clazz = Class.forName("com.simple.SUV");
            //获取实例(JDK 1.9推荐使用,可以根据参数不同,调用不同的构造方法)
            suv = (SUV) clazz.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            //不存在这个类
            System.out.println("没有这款SUV!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回引用指向的实例
        return suv;
    }
}

HatchbackFactory类

public class HatchbackFactory implements CarFactory{
    //方法的具体实现
    @Override
    public Car createCar() {
        //定义引用
        Hatchback hatchback = null;
        try {
            //反射获取Class对象(包名 + 类名)
            Class clazz = Class.forName("com.simple.Hatchback");
            //获取实例(JDK 1.9推荐使用,可以根据参数不同,调用不同的构造方法)
            hatchback = (Hatchback) clazz.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            //不存在这个类
            System.out.println("没有这款小轿车!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回引用指向的实例
        return hatchback;
    }
}

测试代码:

//定义工厂引用
CarFactory factory = null;
//指向SUV工厂
factory = new SUVFactory();
factory.createCar().run();
//指向Hatchback工厂
factory = new HatchbackFactory();
factory.createCar().run();

运行结果
运行结果

3、优点

  • 工厂方法模式中,工厂方法用以创建客户所需要的产品,同时还向客户隐藏了具体产品实例化这一细节,用户只需知道对应工厂。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键,它能够让工厂自主确定创建对象类型,其完全被封闭在工厂内部,故该模式又被称为 多态工厂模式
  • 引入新产品无需修改抽象工厂,无需修改其他继承产品,只需添加一个具体工厂和具体产品即可,扩展性非常好,符合开闭原则。

4、缺点

  • 添加新产品具体类,必须提供对应的工厂,添加了系统的复杂度。

三、抽象工厂模式(工具模式)

抽象工厂模式(Abstract Factory Pattern) / 工具模式(Kit Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

1、结构

  • AbstractFactory(抽象工厂):
    声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
  • ConcreteFactory(具体工厂):
    实现抽象工厂的方法,可生成具体产品,这些产品故成了一个产品族。
  • AbstractProduct(具体产品):
    为每种产品声明接口,在抽象产品中声明了产品所有的业务方法。
  • ConcreteProduct(具体产品):
    定义具体工厂生产的具体产品对象,实现抽象产品中定义的业务方法。

抽象工厂模式

2、举例

实现

样品代码:
Car接口:

public interface Car {
    //定义同一方法
    void run();
}

SUV接口:

public interface SUV extends Car {
    //定义 SUV 特殊方法
    void load();
}

Hatchback接口:

//定义 Hatchback 特殊方法
    void hatch();

BrandASUV类:

public class BrandASUV implements SUV {
    @Override
    public void run() {
        System.out.println("A品牌SUV跑起来!");
    }

    @Override
    public void load() {
        System.out.println("A品牌SUV容载货物!");
    }
}

BrandAHatchback类:

public class BrandAHatchback implements Hatchback {
    @Override
    public void run() {
        System.out.println("A品牌小轿车跑起来!");
    }

    @Override
    public void hatch() {
        System.out.println("A品牌小轿车打开后备箱!");
    }
}

BrandBSUV类:

public class BrandBSUV implements SUV{
    @Override
    public void run() {
        System.out.println("B品牌SUV跑起来!");
    }

    @Override
    public void load() {
        System.out.println("B品牌SUV容载货物!");
    }
}

BrandBHatchback类:

public class BrandBHatchback implements Hatchback{
    @Override
    public void run() {
        System.out.println("B品牌小轿车跑起来!");
    }

    @Override
    public void hatch() {
        System.out.println("B品牌小轿车打开后备箱!");
    }
}

CarFactory接口:

public interface CarFactory {
    SUV createSUV();
    Hatchback createHatchback();
	//定义同一造车模板(减少代码冗余),如子类有需要,可随时重写该方法
    default Car createCar(String carType) {
        //方法的具体实现
        //定义引用
        Car car = null;
        try {
            //反射获取Class对象(包名 + 类名)
            Class clazz = Class.forName("com.simple." + carType);
            //获取实例(JDK 1.9推荐使用,可以根据参数不同,调用不同的构造方法)
            car = (Car) clazz.getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            //不存在这个类
            System.out.println("没有这款车型!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //返回引用指向的实例
        return car;
    }
}

BrandAFactory类:

public class BrandAFactory implements CarFactory{
	@Override
    public SUV createSUV() {
        return (BrandASUV) createCar("BrandASUV");
    }

    @Override
    public Hatchback createHatchback() {
        return (BrandAHatchback) createCar("BrandAHatchback");
    }
}

BrandBFactory类:

public class BrandBFactory implements CarFactory {
    @Override
    public SUV createSUV() {
        return (BrandBSUV) createCar("BrandBSUV");
    }

    @Override
    public Hatchback createHatchback() {
        return (BrandBHatchback) createCar("BrandBHatchback");
    }
}

测试代码:

CarFactory factory = null;
factory = new BrandAFactory();

Hatchback hatchbackA = factory.createHatchback();
hatchbackA.run();
hatchbackA.hatch();

SUV suvA = factory.createSUV();
suvA.run();
suvA.load();

System.out.println("-------------------");

factory = new BrandBFactory();
Hatchback hatchbackB = factory.createHatchback();
hatchbackB.run();
hatchbackB.hatch();

SUV suvB = factory.createSUV();
suvB.run();
suvB.load();

测试结果:
测试结果

3、优点

  • 隔离了具体类的生成,使得客户并不需要知道什么被创建。这种隔离使得更换一个工厂相对容易,所有具体工厂都实现了抽象工厂的接口。
  • 当一个产品族的多个对象一起工作时,能够保证客户端始终只使用同一个产品族中的产品。

4、缺点 — 开闭原则倾斜性

若在第2小节举例中,添加一种新的车型,首先要修改抽象工厂接口CarFactory,其次要逐个修改具体工厂类,实现相应方法创建新的车型。

抽象工厂无法解决此问题,这是它最大的缺点。在抽象工厂中,添加产品族(例中表现为品牌)很简单,但是增加 新的产品等级结构(例中表现为新的车型)很麻烦,这种性质称为: 开闭原则倾斜性

  • 增加产品族 :抽象工厂很好的支持了开闭原则,只需增加具体产品并对应增加一个新的具体工厂,对已有代码无需做任何修改。
  • 增加新的产品等级结构 : 增加新的产品等级结构,需要修改所有工厂类(抽象工厂类 + 具体工厂类)增加生产新产品的方法,违背了开闭原则。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值