工厂模式是设计模式中最最常用的一种,属于对象创建型设计模式,简单说就是一种不使用new关键字创建对象的设计模式,其用意为解耦,降低代码重构难度。
工厂模式分为简单工厂、工厂方法。
简单工厂模式的起源很简单,假设一种场景:对象X中调用对象Y和Z,Y和Z同时继承了M对象。最简单的做法为在X中分别new出Y和Z的新对象,这种方法分别调用了Y和Z的构造方法,使用起来很方便,但以后如果想修改Y为Z,则修改的难度就会与调用Y的次数成正比。那么有没有一种方法,能在一个地方修改,即可将new Y全部修改成new Z呢?
这就是工厂模式的起源。简单工厂的做法很直观,就是使用一个工厂类来创建Y和Z对象。通过传入特定字段的判断,来创建不同的对象,在使用时,外部使用共同父类M接收返回的对象即可。
简单工厂模式有三个角色:
工厂类:负责根据特定的标志生成不同的对象实例;
共同父类:拥有子类共同属性,用于工厂模式调用时接收实例;
具体子类:实现各个子类特定属性
举一个例子:有一个CarFactory负责生产不同品牌的汽车,根据客户传入汽车品牌,生产不同品牌汽车实例。汽车对象有bwm和audi两种,拥有共同父类Car。实例代码如下:
//接口父类
public interface Car {
void printBrand();
}
//bwm子类
public class Bmw implements Car {
public void printBrand() {
System.out.println("this is a bmw Car");
}
}
//audi子类
public class Audi implements Car {
public void printBrand() {
System.out.println("this is an audi Car");
}
}
//工厂方法
public class CarFactory {
public static Car produceCar(String brand){
if ("bwm".equalsIgnoreCase(brand)){
return new Bmw();
}else if ("audi".equalsIgnoreCase(brand)){
return new Audi();
}else {
return null;
}
}
}
调用方法如下:
public static void main(String[] args){
Car car1 = CarFactory.produceCar("audi");
Car car2 = CarFactory.produceCar("bwm");
car1.printBrand();
car2.printBrand();
}
运行 结果如下:
this is an audi Car
this is a bmw Car
以上实例可以看出,工厂类并没有任何业务实现,只是提供了生产对象的方式。如果要将对应的汽车修改为另外的,我们只要修改传入工厂的方法即可。但如果我的汽车品牌有1000个呢?要使用1000个if…else if也太扯淡了。那么我们这种简单工厂模式是不是不实用呢?不是的,进行一些优化就可以很方便地使用了。对这种形式的优化首先会想到泛型,但比泛型的更合适的是反射。
使用反射方式首先要修改工厂方法:
public class CarFactory {
public static Car produceCar(String carClassName) throws Exception{
Class> clazz = Class.forName(carClassName);
return (Car)clazz.newInstance();
}
}
调用方式为:
public static void main(String[] args) throws Exception{
Car car1 = CarFactory.produceCar("com.test.Audi");
Car car2 = CarFactory.produceCar("com.test.Bwm");
car1.printBrand();
car2.printBrand();
}
运行结果与上面一样。有同学可能发现了,使用反射需要全限定类名,那么写那么多全限定类名是不是太累了?对的,对这种全限定类名,可以使用一个常量类将其设置为常量,或是使用配置文件,这样是不是很方便?
当然,使用反射的方式只是其中一种方法,更好的方式请看下节,工厂方法。
前文所说,简单工厂存在一系列的缺陷,总结下大体可以分为以下三种:
工厂方法模式与简单工厂模式不同,通过定义父类工厂定义创建对象的接口,生成具体对象则由子类负责。其实就是将简单工厂的方法抽象为接口,通过多态即可实现多种子类不同实现。所以工厂方法也称为多态工厂。
工厂方法模式需要以下四种角色:
接下来用一个例子说明,还是用之前生产汽车的例子,我们在品牌之上再加一个车辆类别,假设有轿车和跑车两种。首先将之前简单工厂的汽车类抽象出来:
public interface Car {
void display();
}
然后具体产品和类别的汽车实现抽象产品来实现:
public class BMWCar implements Car{
public void display() {
System.out.println("This is a car of bmw!");
}
}
public class BMWSuperCar implements Car{
public void display() {
System.out.println("This is a super car of bmw!");
}
}
public class AudiCar implements Car{
public void display() {
System.out.println("This is a car of audi!");
}
}
public class AudiSuperCar implements Car{
public void display() {
System.out.println("This is a super car of audi!");
}
}
实现了抽象产品和具体产品之后,定义公共的抽象工厂角色,如下:
public interface AbstartCarFactory {
Car product(String classic);
}
具体工厂实现如下:
public class BMWFactory implements AbstartCarFactory{
public Car product(String classic){
if ("superCar".equalsIgnoreCase(classic)){
return new BMWSuperCar();
}else if ("car".equalsIgnoreCase(classic)){
return new BMWCar();
}
return null;
}
}
public class AudiFactory implements AbstartCarFactory{
public Car product(String classic){
if ("superCar".equalsIgnoreCase(classic)){
return new AudiSuperCar();
}else if ("car".equalsIgnoreCase(classic)){
return new AudiCar();
}
return null;
}
}
至此,工厂方法的四个角色全部定义完毕,接下来就是调用了。比如要生产一辆宝马的跑车和一辆奥迪的轿车,调用可以如下:
public class CarTest {
public static void main(String[] args) throws Exception{
//宝马车
AbstartCarFactory bwmFactory = new BMWFactory();
Car car1 = bwmFactory.product("superCar");
car1.display();
AbstartCarFactory audiFactory = new AudiFactory();
Car car2 = bwmFactory.product("car");
car2.display();
}
}
得到输出如下:
This is a super car of bmw!
This is a car of bmw!
可以看出,工厂方法模式比简单工厂结构更加清晰,如果要增加新的产品,工厂方法更加方便。其实类别也可以抽象出来,这里就不一一演示了。抽象工厂和抽象产品,不一定是接口,也可以是抽象类或者普通类。java8中增加了default使得接口方法不一定每个子类都要实现,所以选择接口会更加清晰。
好了,以上就是工厂模式的全部内容了,希望大家喜欢。