简单工厂模式、工厂方法模式、抽象工厂模式都属于创建型模式。创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需要知道商品是怎么生产出来一样,因为它们由专门的厂商生产。
1 工厂设计模式
工厂模式分为简单工厂模式,工厂方法模式和抽象工厂模式,它们都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,目的是降低系统代码的耦合程度,并且增强了系统的扩展性。
1.1 简单工厂设计模式
简单工厂模式的最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会十分复杂。工厂设计模式适用于创建的过程十分复杂,但是需要的结果比较单一的情况。比如创建一辆车,我需要设置一堆的颜色、时速、外观类型、种类等等,创建过程十分复杂。
以造汽车为例子,如果我们需要各式各样的汽车,那么我们可以写一个造车工厂来实现汽车对象的创建。
package com.hj;
//首先创建一个汽车的接口
public interface Car {
/*
* 汽车启动方法
* */
void run();
}
接下来写一个奔驰类和宝马类来实现该接口
package com.hj;
//奔驰类
public class Benz implements Car {
private String color = "red";
private double speed = 128;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public void run() {
System.out.println(this.color + "色的" + "奔驰启动了!" + "时速为:" + this.speed + "km/h");
}
}
package com.hj;
//宝马类
public class BMW implements Car{
//可能有一堆的成员变量
private String color="red";
private double speed=128;
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public void run(){
System.out.println(this.color+"色的"+"宝马启动了!"+"时速为:"+this.speed+"km/h");
}
}
然后按照一般的情况,java里创建一个宝马对象是这样的。比如我想要一辆红色的时速为128km/h的宝马汽车,我必须这么写:
import com.hj.BMW;
import com.hj.Car;
public class Client {
public static void main(String[] args) {
// 没有使用工厂方式的创建宝马方法,一堆的set方法,每个车都很复杂
BMW car = new BMW();
car.setColor("red");
car.setSpeed(128);
car.run();
}
}
看起来好像不错,但是每一次都要去setColor和setSpeed。如果我要一百辆车,那我需要set一百次。而且这一百次的代码都是重复的。那么重复的代码我们可以抽象出来,制造一个造车工厂!
package com.hj;
// CarFactory类,用来造车
public class CarFactory {
public Car carFactoryBuild(String type, String color, double speed) {
if (type.equals("BMW")) {
//如果传进来的是宝马,我就创建宝马
BMW car = new BMW();
car.setSpeed(speed);
car.setColor(color);
return car;
} else if(type.equals("Benz")){
Benz car=new Benz();
car.setSpeed(speed);
car.setColor(color);
return car;
}else return null;
}
public Car carFactoryBuild(String type, String color) {
if (type.equals("BMW")) {
//如果传进来的是宝马,我就创建宝马
BMW car = new BMW();
car.setColor(color);
return car;
}else if(type.equals("Benz")){
Benz car=new Benz();
car.setColor(color);
return car;
} else return null;
}
public Car carFactoryBuild(String type, double speed) {
if (type.equals("BMW")) {
//如果传进来的是宝马,我就创建宝马
BMW car = new BMW();
car.setSpeed(speed);
return car;
}else if(type.equals("Benz")){
Benz car=new Benz();
car.setSpeed(speed);
return car;
} else return null;
}
public Car carFactoryBuild(String type) {
if (type.equals("BMW")) {
//如果传进来的是宝马,我就创建宝马
return new BMW();
}else if(type.equals("Benz")){
return new Benz();
} else return null;
}
}
好了,我们现在利用这个工厂去创建我们的汽车!
import com.hj.Car;
import com.hj.CarFactory;
public class Client {
public static void main(String[] args) {
// 创建一个造车工厂,这样就可以很快速地生成想要的车了
CarFactory carFactory = new CarFactory();
// 我就想要一辆宝马,参数随意
Car car1 = carFactory.carFactoryBuild("BMW");
car1.run();
// 我就想要一辆绿色的时速为150km/h的宝马
Car car2 = carFactory.carFactoryBuild("BMW", "green", 150);
car2.run();
// 甚至可以再来一辆黑色的奔驰
Car car3 = carFactory.carFactoryBuild("Benz", "black");
car3.run();
// 来一辆黑色的时速150km/h的奔驰
Car car4 = carFactory.carFactoryBuild("Benz", "black", 150);
car4.run();
}
}
可以看到,我们只需要创建一次工厂,后面就可以让工厂来为我们快速生成一个汽车对象了。有的人可能会觉得这样做反而更复杂了,那是因为这个汽车的属性才只有颜色和时速两个,若是还有轮胎材料、空调、联网类型、窗户样式、等等几百个参数。这样可以省去很多次set方法。
简易代码一览
//汽车工厂
public class CarFactory {
public Car carFactoryBuild(String type, String color, double speed) {
if ("BMW".equals(type)) {//小细节,如果type是null这样写不会报空指针异常,反过来就会报
//如果传进来的是宝马,我就创建宝马
BMW car = new BMW();
car.setSpeed(speed);
car.setColor(color);
return car;
} else if("Benz".equals(type)){
Benz car=new Benz();
car.setSpeed(speed);
car.setColor(color);
return car;
}else return null;
}
public Car carFactoryBuild(String type, String color) {
if ("BMW".equals(type)) {
//如果传进来的是宝马,我就创建宝马
BMW car = new BMW();
car.setColor(color);
return car;
}else if("Benz".equals(type)){
Benz car=new Benz();
car.setColor(color);
return car;
} else return null;
}
public Car carFactoryBuild(String type, double speed) {
if ("BMW".equals(type)) {
//如果传进来的是宝马,我就创建宝马
BMW car = new BMW();
car.setSpeed(speed);
return car;
}else if("Benz".equals(type)){
Benz car=new Benz();
car.setSpeed(speed);
return car;
} else return null;
}
public Car carFactoryBuild(String type) {
if ("BMW".equals(type)) {
//如果传进来的是宝马,我就创建宝马
return new BMW();
}else if("Benz".equals(type)){
return new Benz();
} else return null;
}
}
小结
优点
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确
- 客户端无需知道所创建具体产品的类名,只需知道参数即可
- 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类
缺点
- 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
应用场景
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。总而言之,我们不希望在new的时候有一堆的复杂的set操作,我们希望把复杂的抽象出来,做成工厂。使用的时候可以用工厂去创建,这样就屏蔽了一些复杂的操作。
1.2 工厂方法模式
我们说过Java开发中要遵循开闭原则,如果将来有一天我想新增一种车,那么就必须修改我的简单工厂里的CarFactory类(上述提到的简单工厂模式的缺点),这太不灵活了,而且我已经写好的代码,根据开闭原则我不应该去修改他。为了解决这些问题,就出现了工厂方法模式。工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
比如在上述的例子中,我们想在宝马和奔驰两种车的基础上,增加本田种类的车。如果在简单工厂模式中,我们只能在CarFactory类中添加一个else if来实现本田车类的判断。
那我们可以将CarFactory进一步抽象,将其变成接口,奔驰有奔驰的工厂、宝马有宝马的工厂、本田有本田的工厂。
首先写一个CarFactory2接口作为工厂的模板。
package com.hj;
public interface CarFactory2 {
// 创建汽车的工厂的接口
Car createCar(String color,double speed);
Car createCar(String color);
Car createCar(double speed);
Car createCar();
}
然后分别实现宝马、奔驰、本田的造车工厂类
package com.hj;
//宝马工厂
public class BMWFactory implements CarFactory2 {
@Override
public Car createCar(String color, double speed) {
BMW bmw = new BMW();
bmw.setSpeed(speed);
bmw.setColor(color);
return bmw;
}
@Override
public Car createCar(String color) {
BMW bmw = new BMW();
bmw.setColor(color);
return bmw;
}
@Override
public Car createCar(double speed) {
BMW bmw = new BMW();
bmw.setSpeed(speed);
return bmw;
}
@Override
public Car createCar() {
return new BMW();
}
}
package com.hj;
//奔驰工厂
public class BenzFactory implements CarFactory2{
@Override
public Car createCar(String color, double speed) {
Benz benz = new Benz();
benz.setSpeed(speed);
benz.setColor(color);
return benz;
}
@Override
public Car createCar(String color) {
Benz benz = new Benz();
benz.setColor(color);
return benz;
}
@Override
public Car createCar(double speed) {
Benz benz = new Benz();
benz.setSpeed(speed);
return benz;
}
@Override
public Car createCar() {
return new Benz();
}
}
package com.hj;
//本田工厂
public class HondaFactory implements CarFactory2{
@Override
public Car createCar(String color, double speed) {
Honda honda = new Honda();
honda.setSpeed(speed);
honda.setColor(color);
return honda;
}
@Override
public Car createCar(String color) {
Honda honda = new Honda();
honda.setColor(color);
return honda;
}
@Override
public Car createCar(double speed) {
Honda honda = new Honda();
honda.setSpeed(speed);
return honda;
}
@Override
public Car createCar() {
return new Honda();
}
}
客户文件里测试:
import com.hj.*;
public class Client2 {
public static void main(String[] args) {
//获得一辆红色的时速200的宝马
CarFactory2 carFactoryBMW = new BMWFactory();
Car bmwCar = carFactoryBMW.createCar("red", 200);
bmwCar.run();
//获得一辆绿色的奔驰
CarFactory2 carFactoryBenz = new BenzFactory();
Car benzCar = carFactoryBenz.createCar("green");
benzCar.run();
//获得一辆时速150的本田
CarFactory2 carFactoryHonda = new HondaFactory();
Car hondaCar = carFactoryHonda.createCar(150);
hondaCar.run();
}
}
简易代码一览
//工厂接口
public interface CarFactory2 {
// 创建汽车的工厂的接口
Car createCar();
}
//具体的工厂
public class BenzFactory implements CarFactory2{
@Override
public Car createCar() {
return new Benz();
}
}
public class BMWFactory implements CarFactory2 {
@Override
public Car createCar() {
return new BMW();
}
}
public class HondaFactory implements CarFactory2{
public Car createCar() {
return new Honda();
}
}
//产品接口(大类)
public interface Car {
void run();
}
public class Benz implements Car {
private String color = "red";
private double speed = 128;
public void run() {
System.out.println(this.color+"色的"+"奔驰启动了!"+"时速为:"+this.speed+"km/h");
}
}
public class BMW implements Car{
private String color="red";
private double speed=128;
@Override
public void run(){
System.out.println(this.color+"色的"+"宝马启动了!"+"时速为:"+this.speed+"km/h");
}
}
public class Honda implements Car {
private String color = "red";
private double speed = 128;
@Override
public void run() {
System.out.println(this.color+"颜色的本田启动了,"+"时速为"+this.speed+"km/h");
}
}
小结
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
应用场景:
- 客户只知道创建产品的工厂名,而不知道具体的产品名(client2.java文件里是不知道Benz类和BMW类的存在的,只出现了BenzFactory类和BMWFactory类)。如宝马工厂、奔驰工厂等。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌,比如奔驰、宝马或者本田。
1.3 抽象工厂模式
可以看到在1.2工厂方法模式中,工厂只能生产汽车这一大类的产品。工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机等。但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调。抽象工厂模式可以打破工厂与产品(大类)一对一的关系,使得一个具体的工厂类可以生产多个大类的产品。比如我宝马工厂不再只能生产汽车,我还可以生产自行车。
也就是我们在工厂接口中多定义一个创建自行车方法。
package com.hj;
//自行车接口
public interface Bike {
/*
* 自行车启动方法
* */
void run();
}
宝马自行车实现类:
package com.hj;
//宝马自行车实现类
public class BMWBike implements Bike {
private String color = "red";
private double speed = 128;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
@Override
public void run() {
System.out.println(this.color+"色的宝马自行车启动了,时速为"+this.speed+"km/h");
}
}
抽象工厂的定义:
package com.hj;
public interface AbstractFactory {
Car createCar(String color,double speed);
Bike createBike(String color,double speed);
}
具体的宝马超级工厂:
package com.hj;
//宝马牌子工厂既可以生产汽车也可以生产自行车
public class BMWSuperFactory implements AbstractFactory {
@Override
public Car createCar(String color, double speed) {
BMW bmw = new BMW();
bmw.setSpeed(speed);
bmw.setColor(color);
return bmw;
}
@Override
public Bike createBike(String color, double speed) {
BMWBike bmwBike = new BMWBike();
bmwBike.setColor(color);
bmwBike.setSpeed(speed);
return bmwBike;
}
}
客户测试文件:
import com.hj.BMWSuperFactory;
import com.hj.Bike;
import com.hj.Car;
public class Client3 {
public static void main(String[] args) {
BMWSuperFactory bmwSuperFactory=new BMWSuperFactory();
//想要一辆绿色的时速60的宝马自行车
Bike bmwSuperFactoryBike = bmwSuperFactory.createBike("green", 60);
bmwSuperFactoryBike.run();
//想要一辆红色的时速150的宝马汽车
Car bmwSuperFactoryCar = bmwSuperFactory.createCar("red", 150);
bmwSuperFactoryCar.run();
}
}
简易代码一览
//抽象工厂
interface AbstractFactory{
Car createCar(String color,double speed);
Bike createBike(String color,double speed);
}
//具体工厂
class BMWSuperFactory implements AbstractFactory{
@Override
public Car createCar(String color, double speed) {
BMW bmw = new BMW();
bmw.setSpeed(speed);
bmw.setColor(color);
return bmw;
}
@Override
public Bike createBike(String color, double speed) {
BMWBike bmwBike = new BMWBike();
bmwBike.setColor(color);
bmwBike.setSpeed(speed);
return bmwBike;
}
}
//产品大类——汽车
interface Car{
void run();
}
public class BMW implements Car {
@Override
public void run(){
System.out.println(this.color+"色的"+"宝马启动了!"+"时速为:"+this.speed+"km/h");
}
}
//产品大类——自行车
interface Bike{
void run();
}
public class BMWBike implements Bike {
@Override
public void run() {
System.out.println(this.color+"色的宝马自行车启动了,时速为"+this.speed+"km/h");
}
}
小结
抽象工厂模式通常适用于以下场景:
- 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
- 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
- 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
抽象工厂其实就是工厂方法的扩展!当抽象工厂只有一种大类产品的时候,它就是工厂方法!