现实中的工厂是一个生产产品的机构,这个工厂可以很大,产品品类非常丰富。我们作为工厂的客户,只需要告诉工厂我们需要什么就可以了,根本不关心工厂是怎么去生产的。
作为代码设计,我们也不希望知道对象是如何生成的,我们只想要一个对象罢了。
现在以汽车厂为例,我们知道汽车厂,像比亚迪这样的,既能生产汽车,又能生产电池。加入我们想要一个比亚迪的汽车,我们就可以告诉比亚迪工厂,我需要一辆比亚迪汽车,至于工厂里采购钢材,采购橡胶,那和我没有任何关系,我只是需要比亚迪汽车。
假设现在吉利也可以造汽车,但是不能造电池。那我需要一辆吉利汽车,也是没有问题的,只是不能在吉利买电池罢了。
不管是比亚迪还是吉利,都是工厂;不管是比亚迪汽车还是吉利汽车,都是汽车;不管是比亚迪电池还是吉利电池,都是电池。
这样我们就能抽象出三个概念来:工厂,汽车和电池。
未来,如果需要特斯拉电池或者汽车,只需要新建一个特斯拉厂就可以了。
下面看看如何利用代码去实现。
- 首先定义一个抽象产品Battery:
package factory;
public abstract class Battery {
private String core;
public Battery(String core) {
this.core = core;
}
public void desc() {
System.out.println("本电池采用了" + core + "电芯");
};
}
- 然后定义一个抽象类Car:
package factory;
public abstract class Car {
private String engine;
private String wheels;
public Car(String engine, String wheels) {
this.engine = engine;
this.wheels = wheels;
}
public void desc() {
System.out.println("这辆车采用了" + engine + "引擎,装配了" + wheels + "轮胎!");
}
}
- 定义抽象工厂:
package factory;
import java.lang.reflect.InvocationTargetException;
//工厂有生产汽车和自行车的能力
public abstract class Factory {
public static Factory getFactory(String factoryName) {
Factory factory = null;
try {
factory = (Factory) Class.forName(factoryName).getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException
| IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return factory;
}
public abstract Car createCar(String engine, String wheels);
public abstract Battery createBattery(String core);
}
抽象工厂用到了反射的办法去生成具体工厂,这样扩展性比较强,未来新增任何工厂,都不用修改抽象工厂类。
- 定义具体的产品:
BydCar.java
package factory;
public class BydCar extends Car {
private String engine;
private String wheels;
public BydCar(String engine, String wheels) {
super(engine, wheels);
this.engine = engine;
this.wheels = wheels;
}
@Override
public void desc() {
System.out.println("比亚迪汽车采用自研" + engine + "发动机,使用" + wheels + "轮胎。");
}
}
BydBattery.java
package factory;
public class BydBattery extends Battery {
private String core;
public BydBattery(String core) {
super(core);
this.core = core;
}
@Override
public void desc() {
super.desc();
}
}
GellyCar.java
package factory;
import java.util.StringJoiner;
public class GellyCar extends Car {
private String engine;
private String wheels;
public GellyCar(String engine, String wheels) {
super(engine, wheels);
this.engine = engine;
this.wheels = wheels;
}
@Override
public void desc() {
System.out.println("吉利汽车采用自研发动机:" + engine + ",使用" + wheels + "轮胎。");
}
@Override
public String toString() {
return new StringJoiner(", ", GellyCar.class.getSimpleName() + "[", "]")
.add("engine='" + engine + "'")
.add("wheels='" + wheels + "'")
.toString();
}
}
- 定义具体工厂:
BydFactory.java
package factory;
public class BydFactory extends Factory {
@Override
public Car createCar(String engine, String wheels) {
return new BydCar(engine, wheels);
}
@Override
public Battery createBattery(String core) {
return new BydBattery(core);
}
}
GeelyFactory.java
package factory;
public class GeelyFactory extends Factory {
@Override
public Car createCar(String engine, String wheels) {
return new GellyCar(engine, wheels);
}
@Override
public Battery createBattery(String core) {
return null;
}
}
到现在为止,所有的类都已经定义好了。下面就是具体的使用了:
package factory;
public class Main {
public static void main(String[] args) {
//新建一个比亚迪的工厂
Factory bydFactory = Factory.getFactory("factory.BydFactory");
//生产比亚迪汽车和电池
Car bydCar = bydFactory.createCar("B3", "邓禄普");
bydCar.desc();
Battery bydBattery = bydFactory.createBattery("三洋");
bydBattery.desc();
//新建一个吉利工厂
Factory geelyFactory = Factory.getFactory("factory.GeelyFactory");
Car geelyCar = geelyFactory.createCar("G1", "固特异");
geelyCar.desc();
}
}
这段代码打印如下:
比亚迪汽车采用自研B3发动机,使用邓禄普轮胎。
本电池采用了三洋电芯
吉利汽车采用自研发动机:G1,使用固特异轮胎。
工厂模式的好处是显而易见的,我们根本不需要关注生产的细节,使用者只需要提供一些原材料就可以了,至于原材料如何组织,那是工厂的事情。还有一点就是添加一个新工厂很容易。
但是工厂模式的缺点也是明显的,就是难以增加新的零件,比如要给汽车生产加一个零件——挡风玻璃——就很难,得要通盘修改。而且实现的具体工厂越多,修改难度就越大。