在java编程中,我们最常用的实例化对象方式就是直接new一个对象,但是有时候我们直接new对象会有些问题,例如:某个对象实例化的时候需要一些其他辅助对象的资源,也就是说这个对象在实例化的时候需要一个过程,而不是一个动作,而工厂模式就是帮我们管理对象的实例化,我们不用管这个对象是怎样实例化的,我们只要告诉工厂,我要用这个对象,你帮我实例化吧。关于这一点,我会在后面用具体例子说明,我先说说工厂设计模式。
工厂模式有三个形态
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
简单工厂模式
简单工厂模式又称为静态工厂模式,它就是定义一个用于创建对象的接口。
它的组成有三部分:
- 工厂角色类
- 产品接口角色类
- 具体产品角色类
就用生产汽车的例子来说明,在没有工厂模式之前,一个人要想要生产一辆车,他需要自己去制造这辆车。
//宝马车类
public class BMW {
public void getName(){
System.out.println("------我是宝马-------");
}
}
//奔驰车类
public class Benz {
public void getName(){
System.out.println("------我是奔驰-------");
}
}
//用户类
public class Customer {
public static void main(String[] args) {
BMW bmw = new BMW();
bmw.getName();
}
}
用户想要这辆车,他得自己去造(去new)。后来这个人他也想为其他人造车,于是他就开了一个工厂,任何用户想要车,只要告诉这个工厂,给我辆车吧,用户自己会不会造车,不用管,工厂全帮他办了。其实这个过程就是降低耦合度的过程,把用户和车之间的耦合降低了。
产品类:
//汽车接口类
public interface Car {
public void getName();
}
public class BMW implements Car{
public void getName(){
System.out.println("------我是宝马-------");
}
}
public class Benz implements Car{
public void getName(){
System.out.println("------我是奔驰-------");
}
}
工厂类:
public class Factory {
public Car create(String carName){
switch (carName) {
case "BMW":
return new BMW();
case "Benz":
return new Benz();
default:
System.out.println(""没有该类汽车的生产资料!无法生产"");
break;
}
return null;
}
}
用户类:
public class Customer {
public static void main(String[] args) {
Factory factory=new Factory();
Car car=factory.create("BMW");
car.getName();
}
}
再后来,用户已经不满足这两款汽车了,用户想要奥迪车,那么这个工厂生产汽车的方法就要进行改造,添加一个奥迪车的判断选择(增加case),然后新增一个奥迪车类实现汽车接口。但是这就有一个问题了,如果以后用户需要更多款式的汽车,我们每次都要修改工厂类,那得累坏我们这些工厂的工人(程序员)。程序设计一般都是要遵循开闭原则(对扩展开放,对修改关闭),很明显这个简单工厂不符合这个原则,每次都要修改工厂类。于是我们就对工厂改造,让它能灵活制造更多类型的汽车。
工厂类:
public class Factory {
public Car create(String carName){
try {
return(Car)Class.forName(carName).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.out.println("没有该类汽车的生产资料!无法生产");
}
return null;
}
}
用户类:
public class Customer {
public static void main(String[] args) {
Factory factory=new Factory();
Car car=factory.create("Benz");
car.getName();
}
}
这样,每次新增一款汽车,我们只要新增这个汽车类实现汽车接口就可以了,用户只要告诉工厂自己想要的汽车产品类型就行。不过这里还有一点不足,用户告知工厂时,需要加上汽车类的路径,这个就比较不友好了。这里我们处理的方式就是增加一个工厂产品清单(car.properties),里面写明该工厂可以生产的汽车,工厂类通过读取这个清单,来制造用户要生产的汽车,这里我就不把实体类粘出来了,大家可以自己试着去实现。
当然我们还可以用另一种方式解决这个问题,那就是工厂方法模式。工厂类定义成了接口,而每增加一款汽车,就增加该车种类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的工厂代码。
工厂方法模式
工厂方法模式就是实现一个工厂接口,然后由具体工厂类去进行产品实例化。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的具体工厂类来分担。其实也可以这样理解,工厂接口就是一个工厂,具体工厂类就是这个工厂的不同部门,比如制造宝马的部门,制造奔驰的部门,以后要是想生产奥迪等其他汽车,可以开对应的部门,每次新增的产品时,就不用修改原来的工厂方法了。
它的组成有四部分:
- 工厂接口类
- 具体工厂角色类
- 产品接口类
- 具体产品角色类
接着上面的例子说,这个时候工厂结构进行改革,保留原来的工厂名称(即工厂接口类),新建了两个部门:生产宝马车的部门和生产奔驰车的部门(即两个具体的工厂角色类)。
工厂类:
interface Factory {
public Car create();
}
//生产宝马车的部门
public class BMWFactory implements Factory {
public Car create() {
return new BMW();
}
}
//生产奔驰车的部门
public class BenzFactory implements Factory {
public Car create() {
return new Benz();
}
}
用户类:
public class Customer {
public static void main(String[] args) {
Factory factory1=new BMWFactory();
Car car1=factory1.create();
car1.getName();
Factory factory2=new BenzFactory();
Car car2=factory2.create();
car2.getName();
}
}
随着工厂的发展,汽车要开始装车载导航了,于是工厂也开始制造自己的导航,分别为适配宝马的导航仪和适配奔驰的导航仪,而且以后要新增的汽车类型越来越多,每个车都要配上对应的车载导航,原来的 工厂方法模式已经不适应了,我们需要新增太多的具体工厂类,这个时候抽象工厂模式就产生了。
抽象工厂模式
抽象工厂模式和工厂方法模式一样,都由四个部分组成,只是抽象工厂模式将产品进行了产品族和产品等级划分。于是该产品就可以这样划分:
新增的导航仪产品类:
//导航仪产品接口
public interface GPS {
public void getName();
}
//适配宝马车的GPS产品
public class GPSBMW implements GPS {
public void getName() {
System.out.println("------我是宝马GPS-------");
}
}
//适配奔驰车的GPS产品
public class GPSBenz implements GPS{
public void getName() {
System.out.println("------我是奔驰GPS-------");
}
}
工厂类:
interface Factory {
public Car createCar();
public GPS createGPS();
}
//宝马车工厂,同时制造宝马车和宝马车GPS
public class BMWFactory implements Factory {
public Car createCar() {
return new BMW();
}
public GPS createGPS() {
return new GPSBMW();
}
}
//奔驰车工厂,同时制造奔驰车和奔驰车GPS
public class BenzFactory implements Factory {
public Car createCar() {
return new Benz();
}
public GPS createGPS() {
return new GPSBenz();
}
}
用户类:
public class Customer {
public static void main(String[] args) {
Factory factory1=new BMWFactory();
Car car1=factory1.createCar();
GPS gps1=factory1.createGPS();
car1.getName();
gps1.getName();
Factory factory2=new BMWFactory();
Car car2=factory2.createCar();
GPS gps2=factory2.createGPS();
car2.getName();
gps2.getName();
}
}
可以看出,每个具体工厂都实现一族产品,相对简单工厂模式,可以少些很多工厂类,而且每次增加新的产品族,只要新增一个对应的实现工厂接口的具体工厂类就行了,但是,抽象工厂有一个弊端,如果新增产品等级的话,就需要修改所有的工厂角色,包括工厂类,这就违背了“开闭原则”。因此抽象工厂模式要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大的修改,为后续维护工作带来诸多麻烦。
用工厂设计模式实例对象和通过new实例对象的一个比较
我就用组装电脑这个场景说明吧。现在我要组装一台电脑,肯定需要CPU,硬盘等等许多组件产品,在没有工厂模式的情况下我们会是怎样去做的呢。
new实现方式:
public class CPU {
public String name="CPU";
}
public class HardPan {
public String name="硬盘";
}
public interface Icomputer {
}
public class Computer implements Icomputer {
public Computer(CPU cpu,HardPan hardPan) {
System.out.println("我是电脑由"+cpu.name+"和"+hardPan.name+"组成。");
}
}
public class My {
public static void main(String[] args) {
CPU cpu=new CPU();
HardPan hardPan=new HardPan();
Icomputer computer=new Computer(cpu, hardPan);
}
}
我们要new一个电脑对象,需要先new硬盘和CPU,而硬盘和CPU与调用者没有关系,他们之间的耦合度太高,而且不易扩展。当然这还是调用者知道怎么组装电脑,在实际情况中,调用者大多是不知道的怎么组装的。这个时候工厂模式的作用就体现出来了,它帮我们new。
工厂模式实现方式:
public interface IFactory {
public Icomputer createComputer();
}
public class Factory implements IFactory {
public Icomputer createComputer() {
CPU cpu=new CPU();
HardPan hardPan=new HardPan();
Icomputer computer=new Computer(cpu, hardPan);
return computer;
}
}
public class My {
public static void main(String[] args) {
IFactory factory=new Factory();
Icomputer computer=factory.createComputer();
}
}
使用工厂方法后,调用端的耦合度大大降低了。