工厂模式的概览图
简单工厂模式
简单工厂模式又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式的实质是由一个工厂类根据传入的参数,决定应该创建哪一个产品类对象。用户无需关心创建的过程,只需使用即可。
写一个简单的Car汽车接口,有不同的实现子类
// 汽车接口
public interface Car {
void run();
}
// 汽车产品一:实现类--BMW
public class Bmw implements Car{
@Override
public void run() {
System.out.println("----宝马车启动----");
}
}
// 汽车产品二:实现类--Benz
public class Benz implements Car{
@Override
public void run() {
System.out.println("----奔驰车启动----");
}
}
// 汽车产品三:实现类--Audi
。。。
静态工厂类:
public class CarStaticFactory {
public static Car getCar(String carName){
if (carName.equals("BMW")){
return new Bmw();
}else if (carName.equals("Benz")){
return new Benz();
}
return null;
}
}
测试类:
public class Test {
public static void main(String[] args) {
Car car = CarStaticFactory.getCar("BMW");
car.run();
}
}
输出:
- 优点:把对类的创建初始化全都交给一个工厂类来完成,用户无需关心创建的过程,降低耦合,将创建与使用分离。
- 缺点:违背了设计模式的“开闭原则”,如果后期需要增加更多的产品类,则必须对工厂类做修改。
改进:为了解决 每增加一个产品,就得修改工厂类,增加一个else if分支,可通过反射创建实例
工厂类增加一个通过类全路径去获取实例(反射)
public class CarStaticFactory {
public static Car getCar(String carName){
if (carName.equals("BMW")){
return new Bmw();
}else if (carName.equals("Benz")){
return new Benz();
}
return null;
}
// 通过反射获取类实例
public static Car getCarByReflect(String classPath){
Car car = null;
try {
Class clazz = Class.forName(classPath);
//创建对象
car = (Car) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return car;
}
}
测试类,当然这里类路径可以放在配置文件中,通过配置文件读取
public class Test {
public static void main(String[] args) {
// 静态工厂
// Car car = CarStaticFactory.getCar("BMW");
Car car = CarStaticFactory.getCarByReflect("com.example.demo.factory.Bmw");
car.run();
}
}
输出:
但这样还是有问题,类的全路径写耦合在代码使用中了,可配置在文件中。
再次改造:增加配置文件,读取配置文件获取对应的类路径变量,再反射创建实例
创建一个配置文件 applicationContext.properties文件
bmw=com.example.demo.factory.Bmw
benz=com.example.demo.factory.Benz
改造工厂类,读取配置文件获取类路径,再通过反射创建实例:
/**
* @description: 模拟bean工厂类
* @author: stwen_gan
* @date:
**/
public class BeanFactory {
/**
* 通过properties类获取配置文件中的配置
*/
private static Properties properties = new Properties();
static {
try {
//1. 获得IO输入流
InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.properties");
//2. 加载流
properties.load(inputStream);
//3. 关闭流
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Car getCarByName(String beanName){
Car car = null;
try {
Class clazz = Class.forName(properties.getProperty(beanName));
//创建对象
car = (Car) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return car;
}
}
测试:
public class Test {
public static void main(String[] args) {
// 静态工厂
// Car car = CarStaticFactory.getCar("BMW");
// Car car = CarStaticFactory.getCarByReflect("com.example.demo.factory.Bmw");
// car.run();
Car bmw =BeanFactory.getCarByName("bmw");
Car benz =BeanFactory.getCarByName("benz");
bmw.run();
benz.run();
}
}
输出:
通过上述的一步步改造,我们实现了一个通用的工厂模式,有点类似Spring容器的实现思路。
其实,Spring在启动时通过xml、JavaConfig、注解扫描等方式注册bean,我们需要某个bean实例时,就可以通过调用getBean方法从ApplicationContext中获取容器的bean对象。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,所以说,虽然简单的静态工厂模式有缺陷,但是正因为它简单方便,可通过一定的改造,在某些场景更实用方便。
工厂方法模式
利用多态的特性,通过实现同一个工厂接口来创建不同的工厂子类型,将 if-else 分支去掉。
将上面的工厂类变为为一个接口或抽象类,由具体不同类型的工厂子类去实现,当需要增加不同的产品实现类时,同时只需要增加多一个工厂子类即可
// 抽象接口
public interface ICarFactory {
Car getCarByFactory();
}
// bmw 工厂子类 (某一类型的工厂,只生产bmw车型)
public class BmwFactory implements ICarFactory{
@Override
public Car getCarByFactory() {
return new Bmw();
}
}
// benz 工厂子类 (某一类型的工厂,只生产benz车型)
public class BenzFactory implements ICarFactory{
@Override
public Car getCarByFactory() {
return new Benz();
}
}
// ....
测试类:
public class Test {
public static void main(String[] args) {
// // 静态工厂
// Car car = CarStaticFactory.getCar("BMW");
// car.run();
// 工厂方法
Car car = new BmwFactory().getCarByFactory();
car.run();
}
}
输出:
- 优点:利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。
- 缺点:会导致工厂类对象的创建耦合到了代码使用方中。每增加一个汽车类,同时也要增加多一个相应的汽车工厂实现类。
抽象工厂模式
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
抽象工厂与工厂方法的区别,就在于产品簇的问题,上面只是能创建汽车这一种产品,假如这时我们需要多了一种产品(如飞机),这时候怎么办呢?可以在抽象工厂里增加一个生产飞机的方法,然后在每个具体工厂子类也增加相应的实现方法,这样的话,缺点很明显,需要修改抽象工厂和具体工厂子类。
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
/**
* @description: 抽象工厂--可生产不同产品组产品
* @author: stwen_gan
* @date:
**/
public interface Factory {
Car getCarByFactory();
Plane getPlaneByFactory();
// 其他产品组。。。
}
// 工厂一:可生产宝马汽车和客机
public class FactoryOne implements Factory{
@Override
public Car getCarByFactory() {
return new Bmw();
}
@Override
public Plane getPlaneByFactory() {
return new AirPlane();
}
}
// 工厂二:可生产奔驰汽车和战斗机
public class FactoryTwo implements Factory{
@Override
public Car getCarByFactory() {
return new Benz();
}
@Override
public Plane getPlaneByFactory() {
return new BattlePlane();
}
}
测试类:
public class Test {
public static void main(String[] args) {
// 抽象工厂
Car car1 = new FactoryOne().getCarByFactory();
car1.run();
Plane plane1 = new FactoryOne().getPlaneByFactory();
plane1.fly();
Car car2 = new FactoryOne().getCarByFactory();
car2.run();
Plane plane2 = new FactoryOne().getPlaneByFactory();
plane2.fly();
}
}
输出:
总结
- 简单工厂 :用来生产同一等级结构中的任意产品,(不支持拓展增加产品)。
- 工厂方法 :用来生产同一等级结构中的固定产品,(支持拓展增加产品) 。
- 抽象工厂 :用来生产不同产品族的全部产品,(不支持拓展增加产品;支持增加产品族)。
实际使用中,需要根据具体的业务场景选择。
●阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路
●SpringCloud电商秒杀微服务-Redisson分布式锁方案
查看更多好文,进入公众号--撩我--往期精彩
一只 有深度 有灵魂 的公众号0.0