工厂模式-从jdk与spring源码解读三种工厂模式

简单工厂模式、工厂方法模式、抽象工厂模式,是一个由简到繁,根据需求的不断复杂化多样化而诞生的过程,工厂模式其实就是根据工厂创建对象,只不过有的是小作坊,有的是大车间

简单工厂模式

简单工厂模式就相当于一个小作坊,客户端给工厂传一个参数(可以是类名,或者类的字节码对象等)

简单工厂模式的代码实现

/**
* 造车的接口
*/
public interface ICar{
	// 造轮胎
	void createWheel();
	// 造发动机
	void createEngine();
}
/**
* 造公交车的类
*/
public class Bus implements ICar{
	// 造轮胎
	public void createWheel(){
		System.out.println("造出一个大巴轮胎");
	};
	// 造发动机
	public void createEngine(){
		System.out.println("造出一个大巴发动机");
	};
}
/**
* 造卡车的类
*/
public class Truck implements ICar{
	// 造轮胎
	public void createWheel(){
		System.out.println("造出一个卡车轮胎");
	};
	// 造发动机
	public void createEngine(){
		System.out.println("造出一个卡车发动机");
	};
}
/**
* 造车工厂
*/
public class CarFactory{
	// 造车方法
	public ICar createCar(Class<? extends ICar> clazz){
		try {
			if (null != clazz)
				return clazz.newInstance();
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}
}
/**
* 客户端
*/
public static void main(String[] args){
	// 创建一个简单工厂,并传入Bus的字节码对象,来获得一个Bus的对象
	CarFactory factory = new CarFactory();
	ICar bus = factory.createCar(Bus.class);
}

这里假设我们创建对象的过程比较复杂,这样的话就相当于把创建对象的过程封装到了工厂中,调用者只需要传入需要的参数即可获得对应的对象实例,不需要关心具体是怎么创建出来的。

简单工厂在JDK中的例子

Calendar

在这里插入图片描述
在这里插入图片描述
createCalendar这个方法,和我们的createCar其实是一样的,他这个里面的逻辑就是为了得到一个Calendar对象。
这里先不讨论具体的创建过程,只关注它的简单工厂思想的部分。
里面还涉及到了其他设计模式,可见我们的设计模式一般是混合使用的。

LoggerFactory

比如我们常用的门面,org.slf4j.LoggerFactory

public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

    public static Logger getLogger(Class<?> clazz) {
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
            Class<?> autoComputedCallingClass = Util.getCallingClass();
            if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
            }
        }

        return logger;
    }

这里的两个getLogger方法也都类似于createCar,只不过是传参的不同而已,方法内不管多复杂,最终都是为了得到一个Logger实例来进行日志的输出,我们的调用是简单的。

// 从工厂获取实例,调用
private final Logger logger = LoggerFactory.getLogger(Test.class);
logger.info("输出了一行日志,行号为{}:",lineNumber);

工厂方法模式

简单工厂模式的不足

简单工厂模式封装了生成bean的过程,但是工厂的职责太重,不利于产品的拓展,只适用单一简单的情况。
比如上面造车的例子,如果我们的产品结构再复杂一点,巴士和卡车的造车组装过程肯定是有所差别的。
这样的话,我们就需要对工厂做如下改造

/**
* 造车工厂
*/
public class CarFactory{
	// 造车方法
	public ICar createCar(Class<? extends ICar> clazz){
		try {
			if (null != clazz)
				if(Bus.class.equals(clazz)){
					//要获取的是巴士,找些巴士司机来进行模拟测评
				}
				if(Truck.class.equals(clazz)){
					//要获取的是卡车,找些卡车司机来进行模拟测评
				}
				// 对应车的组装前置过程完成后,再返回实例
				return clazz.newInstance();
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return null;
	}
}

这样当然是没有问题的,但是如果我们再增加一种产品-吉普车(Jeep),那么就又需要改造工厂类了。如果这个时候,对巴士的改造过程也要做改变,把司机车龄限制成10年以上…
反正都要改这个CarFactory,容易引起代码冲突不说,还很混乱,容易对之前的功能也造成影响。
这很显然不符合我们的开闭原则。
所以这个时候就需要把能抽象的抽象一下,能解耦的解耦,能分离的分离

/**
* 造车工厂接口
*/
public interface ICarFactory{
	// 造车方法
	public ICar createCar(){}
}
/**
* 巴士工厂接口
*/
public class BusFactory implements ICarFactory{
	// 造车方法
	public ICar createCar(){
		//找些巴士司机来进行模拟测评
	}
}
/**
* 卡车工厂接口
*/
public class TruckFactory implements ICarFactory{
	// 造车方法
	public ICar createCar(){
		//找些卡车司机来进行模拟测评
	}
}
/**
* 客户端
*/
public static void main(String[] args){
    // 由客户端来决定实例化哪个工厂
	CarFactory factory = new BusFactory();
	ICar bus = factory.createCar(Bus.class);
}

这样如果我们要再增加一个吉普,只需要再增加一个类就行,不需要改其他代码,不用担心对Bus或者Truck的已有逻辑造成影响

JDK中的例子

ILoggerFactory

在这里插入图片描述
还是我们的日志,其实日志系统是一个很好的学习设计模式的例子。
具体的实现不用管,通过类图,我们能清楚的看到,SubstituteLoggerFactory和NOPLoggerFactory都实现了ILoggerFactory这个工厂接口。正是我们上面说的工厂方法模式。

抽象工厂模式

抽象工厂是什么

其实,个人感觉无需太过纠结具体定义。抽象工厂顾名思义就是在工厂方法模式的基础上,更加抽象了一步,业务场景更复杂一些。
从简单工厂到工厂方法模式,我们把一个大而全的工厂抽象成了具体的功能的工厂。那么工厂抽象出来了,再抽象还能抽象什么呢?
没错,就是每个具体的产品中的方法

/**
* 造公交车的类
*/
public class Bus implements ICar{
	// 造轮胎
	public void createWheel(){
		System.out.println("造出一个大巴轮胎");
	};
	// 造发动机
	public void createEngine(){
		System.out.println("造出一个大巴发动机");
	};
}
/**
* 造卡车的类
*/
public class Truck implements ICar{
	// 造轮胎
	public void createWheel(){
		System.out.println("造出一个卡车轮胎");
	};
	// 造发动机
	public void createEngine(){
		System.out.println("造出一个卡车发动机");
	};
}

只要有相似重复可拓展的东西,都可以抽象。我们可以吧轮胎、卡车等具体方法抽象出来
我们先把公交车和卡车的类稍作改造,让它变得贴近一些实际场景。

/**
* 大巴轮胎
*/
public class BusWheel{
	// 设置形状
	void setShape(...);
	// 设置尺寸
	void setSize(...);
	// 进行公交车特有质量检测
	void excuteCheckForBus(...);
}
/**
* 卡车轮胎
*/
public class TruckWheel{
	// 设置形状
	void setShape(...);
	// 设置尺寸
	void setSize(...);
}

BusWheel

/**
* 造公交车的类
*/
public class Bus implements ICar{
	// 造轮胎
	public void createWheel(){
		return new BusWheel();
	};
	// 造发动机
	public void createEngine(){
		return new BusEngine();
}
/**
* 造卡车的类
*/
public class Truck implements ICar{
	// 造轮胎
	public void createWheel(){
		return new TruckWheel();
	};
	// 造发动机
	public void createEngine(){
		return new TruckEngine();
	};
}

我们这里以轮胎为例,BusEngine和TruckEngine暂时省略。
这里的Bus就是一个产品族,BusWheel是一个产品
同样Truck也是一个产品族,TruckWheel也是一个产品
这个时候我们改造完成了,怎么抽象呢?
我们发现,大巴和卡车的轮胎制造流程很相似,所有设置尺寸和设置形状的方法,那完全可以抽象一个接口出来。

/**
* 汽车轮胎标准接口
*/
public interface Wheel{
	// 设置形状
	void setShape();
	// 设置尺寸
	void setSize();
}
/**
* 大巴轮胎
*/
public class BusWheel implements Wheel{
	// 设置形状
	void setShape(...);
	// 设置尺寸
	void setSize(...);
	// 进行公交车特有质量检测
	void excuteCheckForBus(...);
}
/**
* 卡车轮胎
*/
public class TruckWheel implements Wheel{
	// 设置形状
	void setShape(...);
	// 设置尺寸
	void setSize(...);
}

这样,就把具体产品抽象出来了,也符合我们的现实场景,比如轮胎是有一个统一生产标准的。
提到统一,我们又想到,如果所有轮胎的形状是一样的,那么是不是可以把这部分实现放在接口中,把他变成一个抽象类?
当然是可以的。
综上,其实就已经是个抽象工厂模式了
抽象工厂比抽象方法模式的便捷处在于,它更贴合现在现实的场景,适应更复杂的业务场景。比如我们如果要把轮胎改成球形而不是圆形,如果不适用抽象工厂模式,则需要修改每一个工厂的createWheel方法,现在只需要修改上层接口就好。

JDK中的应用

Collection

在这里插入图片描述
Collection对应Wheel,下面三个可以对应BusWheel、TruckWheel、JeepWheel等。
如果再有个获取List的工厂(源码我找了半天没找到类似的),比如ListFactory、QueueFactory、SetFactory,这就是一个完整的抽象工厂了

小结

其实通过分析以及阅读源码,我们发现了几点

  • 设计模式一般都是混合使用的
  • 三种工厂模式的区别其实没那么重要,重要的是我们实际场景中,需要抽象到哪一步,三者只是抽象程度不同而已
  • 没有哪种比哪种好,甚至有时候用设计模式不一定就便捷,杀鸡焉用宰牛刀,适合最重要
  • 设计模式提供的更多是贴合几大原则的设计思路,而不是死搬硬套的去套,这点从源码的实现上也可以看出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

unhappy404

感谢老板打赏!!!爱您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值