是什么?
工厂模式的目的是将创建对象的具体过程隐藏起来,从而达到更高的灵活性
工厂模式分为:简单工厂模式、工厂方法模式、抽象工厂模式;
为什么?
在Java中,万物皆是对象,我们在使用的时候这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,那么所有new的地方都需要修改一遍,这明显违背了设计原则中的开闭原则,如果我们使用工厂来生产对象,那么我们只需要和工厂打交道就好了,彻底和对象解耦,如果要更换对象,直接在工厂中更换该对象即可,达到了与该对象解耦的目的,因此工厂模式最大的优点就是:解耦;
简单工厂模式
简单工厂不是一个设计模式,它更像是一种编码习惯;
结构
抽象产品:定义了产品的规模,描述了产品的主要特性和功能。
具体产品:实现或者继承抽象产品的子类。
具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。
实现
产品类:
public class Car { //汽车父类
private String getName;
}
public class Tesla extends Car{ //子类-特斯拉汽车
public Tesla() {
System.out.println("()=>制造特斯拉汽车");
}
}
public class Benz extends Car{ //子类-奔驰汽车
public Benz() {
System.out.println("()=>制造奔驰汽车");
}
}
工厂类及用户使用:
public class SimpleFactory {
/**
* 。模拟简单工厂模式
* */
public Car getCar(String type){ //汽车“生产间”=》简单工厂
if ("Benz".equals(type)){
return new Benz();
}if ("Tesla".equals(type)){
return new Tesla();
}
return new Car();
}
}
public class Customer {
//消费者直接调用的是工厂而非对象本身,这样就将用户和创建对象的过程隔离开来了
public static void main(String[] args) {
SimpleFactory simpleFactory = new SimpleFactory();
simpleFactory.getCar("Benz");
}
}
优缺点
我们会发现,在简单工厂模式中,提供了专门的工厂类来帮助我们创建对象,实现了对象创建和用户使用的职责分离,客户端不需要知道所创建的产品类名以及创建过程,只需要知道具体产品类所需要的参数即可,通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性;
但是这样做也是不符合“开闭原则的”,如果我们这个时候需要再添加一个BMW汽车,那么同样的需要去修改我们的工厂类,在产品类型较多的时候,有可能造成工厂逻辑过于复杂,不利于系统的横向扩展和维护,并且工厂类集中了所有产品的创建逻辑,如果不能正常工作那么整个系统都会受到影响;
为了解决简单工厂出现的问题,引入了我们的工厂方法模式;
工厂方法模式
定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象,工厂方法使一个产品类的实例化延迟到其工厂的子类;
结构
抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品;
具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建;
抽象产品:定义了产品的规范,描述了产品的主要特性和功能;
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应;
实现
产品类:
public class Car {// 产品父类
}
public class Benz extends Car{ //子类产品
public Benz() {
System.out.println("()=>制造奔驰汽车");
}
}
public class Tesla extends Car{ //子类产品2
public Tesla() {
System.out.println("()=>制造特斯拉汽车");
}
}
抽象工厂
public interface AbstractFactoryInterface { //抽象工厂
Car createCar();
}
具体工厂及用户使用
public class BenzFactory implements AbstractFactoryInterface{ //具体子类工厂
@Override
public Car createCar() {
return new Benz();
}
}
public class TeslaFactory implements AbstractFactoryInterface{ //具体子类工厂2
@Override
public Car createCar() {
return new Tesla();
}
}
public class Customer { //用户类
public static void main(String[] args) {
Car car = new BenzFactory().createCar();
Car car2 = new TeslaFactory().createCar();
}
}
那么我们这个时候还需要添加一个BMW车的话,只需要创建一个BMW类去继承Car,并且再去创建一个BMW的工厂去实现抽象工厂即可,不需要去修改原来的代码,问题即得到解决;
优缺点
用户只需要知道具体工厂的名称即可得到所要的产品,也不需要知道产品具体的类和创建过程,在系统增加新的产品的时候只需要添加具体产品类和对应具体工厂类,无需对源代码进行任何修改,满足开闭原则;
但是每增加一个产品就需要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度;
抽象工厂模式
我们前面介绍的工厂方法模式中考虑的是一类产品的生产,如车厂只生产车,畜牧场只生产动物;
这些工厂只生产同种类的产品,也就是说工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂都是综合型的工厂,能够生产多等级的产品,例如一个畜牧场它不仅生产动物,还生产饲料粮食,汽车厂不仅生产汽车,还生产发动机、汽车配饰等等;
因此抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族如下:横轴是产品等级,也就是同一类产品,纵轴是产品族,也就是同一品牌的产品(产自同一个工厂);
也就是说它是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构;
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可以生产多个等级的产品;
结构
抽象工厂:提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品;
具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建;
抽象产品:定义了产品的规模,描述的产品的主要特性和功能,抽象工厂模式中有多个抽象产品;
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它与具体工厂之间是多对一的关系;
实现
也就是说我们现在车厂不仅要生产车,还要生产车的配饰、配件等等;
抽象产品及具体产品
public class Engine {
public Engine() {
}
}
public class V12Engine extends Engine{
public V12Engine() {
System.out.println("这是V12发动机");
}
}
public class V8Engine extends Engine{
public V8Engine() {
System.out.println("这是V8发动机");
}
}
public class Acc {
public Acc() {
}
}
public class Cowhide extends Acc{
public Cowhide() {
System.out.println("这是牛皮坐垫");
}
}
public class Common extends Acc{
public Common() {
System.out.println("这是普通坐垫");
}
}
抽象工厂
public interface AbstractFactory {
//抽象工厂,定义创建具体工厂的规范
Acc createAcc();
Engine createEngine();
}
具体工厂
public class TeslaFactory implements AbstractFactory{
//不同的具体产品根据自己的生产需求去创建不同的对象
@Override
public Acc createAcc() {
return new Cowhide();
}
@Override
public Engine createEngine() {
return new V12Engine();
}
}
public class BMWFactory implements AbstractFactory{
@Override
public Acc createAcc() {
return new Common();
}
@Override
public Engine createEngine() {
return new V8Engine();
}
}
用户
public class Customer {
public static void main(String[] args) {
TeslaFactory teslaFactory = new TeslaFactory();
teslaFactory.createEngine();
teslaFactory.createAcc();
System.out.println("————————————————————————");
BMWFactory bmwFactory = new BMWFactory();
bmwFactory.createAcc();
bmwFactory.createEngine();
}
}
优缺点
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象;
但是当产品组中需要增加一个新的产品时所有的工厂类都需要进行修改;
例如我如果想要再添加一个空调这个产品,不仅需要多一个空调的产品族,并且在抽象工厂中还需要添加一个创建空调的方法;