工厂模式从名字就能看出,这种模式是用于创建对象的,因为现实生活中,工厂就是用于生产产品的嘛。所以工厂模式的名字起得非常的贴近生活。工厂模式根据应用场景的不同,分为简单工厂,工厂方法,和抽象工厂三种。现实生活中的工厂有的可以生产几种产品,客户根据工厂提供的产品定制就行。比如生产A,B两种品牌的车。这种情况对应到工厂设计模式中就是简单工厂模式。用户只需要给工厂说我要A或者B品牌的车就行。但是如果用户说我想要C品牌的车,这时就难受了,工厂得需要做改建,增加C品牌产线等工作,非常繁琐,于是就出现了特定的工厂,比如生产A品牌车的工厂,生产B品牌的工厂。但是工厂也不能乱建,必须按照总公司的标准建造。所以这种工厂对应到设计模式中就是工厂方法模式,当用户需要新品牌的车时,直接按照总公司标准建造新的工厂就行,不影响之前的工厂工作。但是这种每新加一个品牌的车就得建一个工厂的方法确实比较奢侈,因为可能没那么多的土地,所以我们就可以让我们的工厂承担更多的任务,比如在造车的同时,咱们还可以造手机。这种工厂对应到设计模式中就是抽象工厂模式。
工厂模式的好处就是客户不需要知道对象的创建过程,只是通过简单的调用就能拿到自己想要的对象,这也是工厂设计模式的初衷,屏蔽复杂的对象构造过程,让调用方能通过简单的接口获取到自己想要的对象。从上面的例子我们也可以得出一个结论,就是根据我们的实际场景选择对应的工厂设计模式。比如就很简单的几个对象,咱们使用简单工厂模式就行。对应到生活中的例子就是,有多少钱,干多少事,本来就只有造两种品牌的车的钱,咱们就不要到处建工厂了。
假如我们要创建的产品不多,只要一个工厂类就可以,这种模式就称为简单工厂模式,比如我们就生产CarA 和CarB两种车,那么直接用一个工厂类就可以了,没有必要花钱建多个工厂。简单工厂的类图如下所示。
根据类图我们用JAVA实现下这个造车的过程。
注意:例子只是为了方便介绍本文的内容,不具有真实造车的参考价值
根据类图,我们首先创建一个接口表示我们要造的所有车具有的行为,比如都需要安装引擎,轮子,刷颜色等行为。
public interface ICar {
// 粉刷车身的颜色
void printColor();
// 安装车的引擎
void installEngine();
// 安装车的轮子
void installWheels();
// 安装车载操作系统
void installSystem();
}
然后创建两个产品CarA和CarB,并且都继承实现ICar的接口。
public class CarA implements ICar {
private String color;
private String engine;
private String wheels;
private String system;
@Override
public void printColor() {
System.out.println("CarA 的颜色是红色");
color = "RED";
}
@Override
public void installEngine() {
System.out.println("安装 CarA 的引擎");
engine = "A-Engine";
}
@Override
public void installWheels() {
System.out.println("安装 CarA 的轮子");
wheels = "A牌轮子";
}
@Override
public void installSystem() {
System.out.println("安装 CarA 的车载系统");
system = "A OS";
}
@Override
public String toString() {
return "CarA{" +
"color='" + color + '\'' +
", engine='" + engine + '\'' +
", wheels='" + wheels + '\'' +
", system='" + system + '\'' +
'}';
}
}
public class CarB implements ICar {
private String color;
private String engine;
private String wheels;
private String system;
@Override
public void printColor() {
System.out.println("CarB 的颜色是蓝色");
color = "Blue";
}
@Override
public void installEngine() {
System.out.println("安装 CarB 的引擎");
engine = "B-Engine";
}
@Override
public void installWheels() {
System.out.println("安装 CarB 的轮子");
wheels = "B牌轮子";
}
@Override
public void installSystem() {
System.out.println("安装 CarB 的车载系统");
system = "B OS";
}
@Override
public String toString() {
return "CarB{" +
"color='" + color + '\'' +
", engine='" + engine + '\'' +
", wheels='" + wheels + '\'' +
", system='" + system + '\'' +
'}';
}
}
然后我们新建一个简单工厂类,通过一个buildCar方法构建我们的CarA和CarB两种车的对象
public class SimpleCarFactory {
public static final String CAR_A = "CAR_A";
public static final String CAR_B = "CAR_B";
public static ICar buildCar(String type){
ICar car = null;
if(CAR_A.equals(type)){
car = new CarA();
}
if(CAR_B.equals(type)){
car = new CarB();
}
if(car != null){
car.printColor();
car.installEngine();
car.installWheels();
car.installSystem();
}
return car;
}
}
我们建立一个Client类演示如何使用简单工厂
public class Client {
public static void main(String[] args) {
// 简单工厂
ICar carA = SimpleCarFactory.buildCar(SimpleCarFactory.CAR_A);
System.out.println("build a car A: " + carA);
ICar carB = SimpleCarFactory.buildCar(SimpleCarFactory.CAR_B);
System.out.println("build a car B: " + carB);
}
运行结果:
对于产品种类相对较少的情况,比如我们做相机开发时,Android的系统相机支持多种种API,Camera1和Camera2以及后面的CameraX,这里我们就可以使用简单工厂模式,去根据具体的应用场景获取对应的CameraA对象。
简单工厂确实简单好用,但是缺点也很明显,每增加一种产品就需要增加一个具体的产品类并且修改工厂类,这违背开闭原则(开闭原则是指我们的程序应该对修改关闭,对扩展开放
),就比如我们此时如果要造CarC,但我们只有一个工厂,所以就需要我们去在当前的工厂上修改以保证能够造CarC产品。这时小伙伴可能会说,那么再建一个工厂生产C产品就行了呀。对的,这就是工厂方法模式。工厂方法模式时对简单工厂模式的进一步抽象化。这样做的好处是可以使我们的程序在不修改原来代码的情况下引进新产品。从而满足开闭原则。这里还是以造车为例子。工厂方法的模式类图如下所示
这里的ICar接口和对象使用的都是简单工厂部分的,代码一样,就不重复贴了。这里只贴新的代码。我们需要建立一个工厂的接口。定义工厂的功能是生产车,后面建造的工厂都必须以这个为标准,不能乱建。
public interface IFactory {
ICar buildCar();
}
建立造CarA产品的工厂
public class ACarFactory implements IFactory{
private ICar mCarA = new CarA();
@Override
public ICar buildCar() {
mCarA.printColor();
mCarA.installEngine();
mCarA.installWheels();
mCarA.installSystem();
return mCarA;
}
}
建立造CarB产品的工厂
public class BCarFactory implements IFactory{
private ICar mCarB = new CarA();
@Override
public ICar buildCar() {
mCarB.printColor();
mCarB.installEngine();
mCarB.installWheels();
mCarB.installSystem();
return mCarB;
}
}
这样我们的工厂方法模式就实现了,这时假如我们要新增一个CarC 产品,我们只需要新增一个工厂类和一个产品C的类就可以了,符合开闭原则,代码如下:
新增产品C:
public class CarC implements ICar {
private String color;
private String engine;
private String wheels;
private String system;
@Override
public void printColor() {
System.out.println("CarC 的颜色是白色");
color = "White";
}
@Override
public void installEngine() {
System.out.println("安装 CarC 的引擎");
engine = "C-Engine";
}
@Override
public void installWheels() {
System.out.println("安装 CarC 的轮子");
wheels = "C牌轮子";
}
@Override
public void installSystem() {
System.out.println("安装 CarC 的车载系统");
system = "C OS";
}
@Override
public String toString() {
return "CarC{" +
"color='" + color + '\'' +
", engine='" + engine + '\'' +
", wheels='" + wheels + '\'' +
", system='" + system + '\'' +
'}';
}
}
建造产品C的工厂:
public class CCarFactory implements IFactory{
private ICar mCarC = new CarC();
@Override
public ICar buildCar() {
mCarC.printColor();
mCarC.installEngine();
mCarC.installWheels();
mCarC.installSystem();
return mCarC;
}
}
同样我们新建一个Client类来演示工厂方法的使用
public class Client {
public static void main(String[] args) {
// 工厂方法
IFactory mFactoryA = new ACarFactory();
ICar mCarA = mFactoryA.buildCar();
System.out.println("工厂方法模式构建 carA: " + mCarA);
IFactory mFactoryB = new BCarFactory();
ICar mCarB = mFactoryB.buildCar();
System.out.println("工厂方法模式构建 carB: " + mCarB);
IFactory mFactoryC = new CCarFactory();
ICar mCarC = mFactoryC.buildCar();
System.out.println("工厂方法模式构建 mCarC: " + mCarC);
}
}
运行结果:
当我们的同种产品比较多的时候,可以考虑使用工厂方法模式,也就是说你开公司,目前只生产A,B两种产品,这两种产品都是车,只是一些构造的工艺技术有不同而已,但是未来你可能会继续增加你的同种类型的产品,比如生产C车,,这种情况就可以考虑使用工厂方法模式。工厂方法模式可以满足我们扩展新产品而不需要修改以前的工厂和产品。简单说就是:如果你造车,你的工厂就只是造车,生产手机,你的工厂就是只生产手机。工厂模式只考虑生产同种等级的产品,但读者可能会想,假如我一个工厂想造车又想生产手机怎么办呢?那就得用到抽象工厂模式了。
如前面所说,工厂方法模式只考虑生产同种等级的产品,比如造车的工厂就只是造车,生产手机的工厂就只是生产手机,但是在我们的现实生活中,许多工厂是综合性的工厂,比如造车的工厂也能造手机。为啥这么设计呢?用工厂方法不是更好吗,想造手机,再建一个造手机的工厂不就行了吗?用毛爷爷的话说,理论上行得通,但实际上不可行,因为现在的很多公司都是综合性的公司,大公司会生产各种各样的产品,要是每种产品就建一个工厂,那么地球上的土地就这么点,哪里够用呀,所以综合性工厂可以解决这个问题。这里我们以造车的例子为基础,为工厂新增一个造手机的功能。类图如下:
基于工厂方法的例子,我们新增一个产品手机,首先定义手机的公共接口:
public interface IPhone {
// 刷上颜色
void printColor();
// 安装系统
void installOS();
}
创建手机A
public class PhoneA implements IPhone{
private String color;
private String systemOs;
@Override
public void printColor() {
System.out.println("粉刷手机颜色为红色");
color = "RED";
}
@Override
public void installOS() {
System.out.println("安装手机的操作系统为Android系统");
systemOs = "Android";
}
@Override
public String toString() {
return "PhoneA{" +
"color='" + color + '\'' +
", systemOs='" + systemOs + '\'' +
'}';
}
}
创建手机B:
public class PhoneB implements IPhone{
private String color;
private String systemOs;
@Override
public void printColor() {
System.out.println("粉刷手机颜色为蓝色");
color = "BLUE";
}
@Override
public void installOS() {
System.out.println("安装手机的操作系统为IOS系统");
systemOs = "IOS";
}
@Override
public String toString() {
return "PhoneB{" +
"color='" + color + '\'' +
", systemOs='" + systemOs + '\'' +
'}';
}
}
然后我们定义我们要建的综合性工厂的标准接口
public interface IAbstractFactory {
ICar buildCar();
IPhone buildPhone();
}
新建两个综合性工厂,A和B,分别生产A品牌的产品和B品牌的产品。
// 生产A品牌的产品
public class AFactory implements IAbstractFactory {
private ICar mCarA =new CarA();
private IPhone mPhoneA = new PhoneA();
@Override
public ICar buildCar() {
mCarA.printColor();
mCarA.installEngine();
mCarA.installWheels();
mCarA.installSystem();
return mCarA;
}
@Override
public IPhone buildPhone() {
mPhoneA.printColor();
mPhoneA.installOS();
return mPhoneA;
}
}
// 生产B品牌的产品
public class BFactory implements IAbstractFactory {
private ICar mCarB =new CarB();
private IPhone mPhoneB = new PhoneB();
@Override
public ICar buildCar() {
mCarB.printColor();
mCarB.installEngine();
mCarB.installWheels();
mCarB.installSystem();
return mCarB;
}
@Override
public IPhone buildPhone() {
mPhoneB.printColor();
mPhoneB.installOS();
return mPhoneB;
}
}
我们新建一个Client的类来演示抽象工厂的使用方法
public class Client {
public static void main(String[] args) {
// 抽象工厂
IAbstractFactory mAFactory = new AFactory();
ICar myAcar = mAFactory.buildCar();
IPhone myAPhone = mAFactory.buildPhone();
System.out.println("A工厂造的车: " + myAcar);
System.out.println("A工厂造的手机: " + myAPhone);
IAbstractFactory mBFactory = new BFactory();
ICar myBcar = mBFactory.buildCar();
IPhone myBPhone = mBFactory.buildPhone();
System.out.println("B工厂造的车: " + myBcar);
System.out.println("B工厂造的手机: " + myBPhone);
}
}
运行结果:
当需要生产多种产品的时候,比如我们的工厂需要造车和造手机时,可以考虑使用抽象工厂模式,比如我们的电器厂,就可以考虑使用抽象工厂模式,因为电器厂既可以生产电视机也能生产空调。,农场也是,农场可以种植物,也可以养动物。
本文主要以造车和手机的例子介绍了工厂模式的三种形式,简单工厂,工厂方法,抽象工厂的实现,并且在每节增加了类图和应用场景。读者可以根据应用场景和类图选择对应的工厂模式应用到自己的项目中,让自己的代码更加优雅和可维护。