意图
提供一个创建一系列相关或相互依赖对象的接口,而无需制定他们具体的类
适用性
一下情况可以使用Abstract Factory模式
一个系统要独立于它的产品的创建、组合和表示时
一个系统要由多个产品系列中的一个来配置时
当你要强调一系列相关的产品对象的设计以便进行联合使用时
当你提供一个产品类库,而指向显示他们的接口而不是实现时`
结构
AbstractProductA 和 AbstractProductB是两个抽象的产品,之所以为抽象,是因为他们都有可能有两种或多种不同的实现,ProductA1、ProductA2和ProductB1、ProductB2 就是对两个抽象产品的具体分类的实现。
AbstractFactory 则是一个抽象的工厂接口,它里面应该包含所有的产品创建的抽象方法。而ConcreteFactory 1 和 ConcreteFactory 2 就是具体的工厂了。
我们通常是在运行时再创建一个 ConcreteFactory 类的实例对象,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应该使用不同的具体工厂。
AbstractFactory模式的优缺点
1、分离了具体的类,解耦
2、易于交换产品系列
3、有利于产品的一致性
4、难以支持新品种的产品
实现
假设你现在是客户,要买一辆车。
public class Client {
public static void main(String[] args){
BenzS600 benzCar = new BenzS600();
benzCar.drive();
}
}
问题在哪里呢,就是我们在代码里面把对象BenzS600直接new出来了,如果我们需求改变,当然这里不明显,你可以理解为,原来我们使用MySql作为数据库,但是现在我们要使用Oracle,那么我们所有的写死的代码全要改,这就是耦合度太高引起的“牵一发而动全身”,现在呢,我们可以使用抽象工厂模式,我们可以通过抽象工厂去获取对应产品的工厂(FerrariFactory),然后具体的工厂去给我们提车,而我们需求变了之后,只需要找到对应的工厂,告诉他们我们要买什么车就行了。
我们现在来设计一下
超级工厂类
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:15
*/
public class FactoryProducer {
public static AbstractFactory getFactory(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class cl = Class.forName(type);
System.out.println("创建工厂" + type);
return (AbstractFactory) cl.newInstance();
}
}
抽象工厂类
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:15
*/
public abstract class AbstractFactory {
public abstract Car getCar(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
工厂类
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:15
*/
public class BenzFactory extends AbstractFactory {
@Override
public Car getCar(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class cl = Class.forName(type);
return (BenzCar) cl.newInstance();
}
}
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:15
*/
public class FerrariFactory extends AbstractFactory {
@Override
public Car getCar(String type) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class cl = Class.forName(type);
return (FerrariCar) cl.newInstance();
}
}
汽车类
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:05
* 最高级的抽象产品
*/
public interface Car {
abstract void drive();
}
法拉利4S
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:07
* 抽象产品
*/
public abstract class FerrariCar implements Car {
}
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:09
* 具体的产品Ferrari430
*/
public class Ferrari430 extends FerrariCar {
@Override
public void drive() {
System.out.println("Ferrari 430 come......");
}
}
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:11
*/
public class FerrariLaFerrari extends FerrariCar {
@Override
public void drive() {
System.out.println("Ferrari LaFerrari come......");
}
}
奔驰4S
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:12
*/
public abstract class BenzCar implements Car {
}
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:13
*/
public class BenzGLS450 extends BenzCar {
@Override
piublic void drive() {
System.out.println("Benz GLS450 come......");
}
}
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:13
*/
public class BenzS600 extends BenzCar {
@Override
public void drive() {
System.out.println("Benz S600 come......");
}
}
买车了
package abstractFactory;
/**
* @Author fitz.bai
* @Date 2018/8/26 15:22
*/
public class Client {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
AbstractFactory abstractFactory = FactoryProducer.getFactory("abstractFactory.FerrariFactory");
Car ferrariCar = abstractFactory.getCar("abstractFactory.Ferrari430");
ferrariCar.drive();
Car ferrariLaFeCar = abstractFactory.getCar("abstractFactory.FerrariLaFerrari");
ferrariLaFeCar.drive();
AbstractFactory abstractFactory1 = FactoryProducer.getFactory("abstractFactory.BenzFactory");
Car benzCar = abstractFactory1.getCar("abstractFactory.BenzS600");
benzCar.drive();
Car benzCar1 = abstractFactory1.getCar("abstractFactory.BenzGLS450");
benzCar1.drive();
}
}
/**
创建工厂abstractFactory.FerrariFactory
Ferrari 430 come......
Ferrari LaFerrari come......
创建工厂abstractFactory.BenzFactory
Benz S600 come......
Benz GLS450 come......
*/
从结果看出,我们首先提供工厂名字,抽象工厂给我们找到了具体的工厂,然后我们又告诉他我们需要什么车,他就给了我我们什么车。
还有一个问题,假如有一天我的项目想进行一个重构,重整类路径,包路径,比方说生产Ferrari430的地方有100处,getCar(type)岂不是要修改100处?当然不用,我们可以写在配置文件里面。
实际应用
JDK中的抽象工厂模式有很多应用,典型的比如线程池。我们使用线程池的时候,可以使用ThreadPoolExecutor,根据自己的喜好传入corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler这几个参数,new出一个指定的ThreadPoolExecutor出来。
JDK给开发者提供了Executors这个类,可以让用户产生ThreadPoolExecutor和使用ThreadPoolExecutor分离开,比如可以让Executors提供一个单线程的线程池Executors.newSingleThreadExecutor()、让Executors提供一个无界线程池Executors.newCachedThreadPool()等,这样,开发者可以不用关心线程池是如何去实现的,直接使用Executors方法提供给开发者的ThreadPoolExecutor就可以了。
可以对照上面的结构图,看看线程池实现的源码,再深入了解AbstractFactory Pattern。