工厂模式是个啥
工厂模式是用工厂方法代替new操作的一种模式,是我们最常用的实例化对象模式了,我们不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂。
工厂模式根据抽象程度不同可以分为
- 简单工厂模式
- 工厂模式
- 抽象工厂模式
实际场景分析
上古之时,天地之间只有女娲一个人,不,只有它一个神。甚是孤单,于是女娲转念一想,这他娘的不是办法呀,得想办法造一些人来陪我玩,要不然无聊死了。于是女娲明确了工作目标:我要造人!
package DesignMode.FactoryMode;
/**
* 女娲的目标是造人,但是还没有想好造什么颜色的人,造出来的人说什么语言
*/
public interface Human {
/**
* 每一个人种皮肤都有对应的颜色
*/
public void getColor();
/**
* 每一个人种都可以说话
*/
public void talk();
}
知道了工作目标之后,女娲又犯难了,我该咋造人呢,嘿嘿嘿…,当然是搞一个阴阳八卦炼丹炉,搞一个造人的配方了。
/**
* 女娲造人的八卦炉,抽象工厂
*/
public abstract class AbstractHumanFactory {
/**
* 造人的抽象方法,其中的"T"表示的是,只要实现了Human接口的类都可以作为参数
* 传入参数必须是Class类型,必须是Human的实现类。
* @param c
* @param <T>
* @return
*/
public abstract <T extends Human> T createHuman(Class<T> c);
}
**
* 造人的配方,它得先继承了阴阳八卦炼丹炉
*/
public class HumanFactory extends AbstractHumanFactory {
@Override
public <T extends Human> T createHuman(Class<T> c) {
Human human = null;
try {
//使用反射创建对象
human = (Human) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) human;
}
这炉子也有了,配方也有了,接下来女娲就要开始造人了。第一次由于女娲经验不足,没有把握好火候,给烤的太轻了,于是造出来了白人
/**
* 白人
* @author lenovo
*/
public class WhiteHuman implements Human {
@Override
public void getColor() {
System.out.println("我是一个白人,我的皮肤是白色的");
}
@Override
public void talk() {
System.out.println("我是一个白人,我说英语");
}
}
女娲十分不服气,既然火候轻了,那我多烤一会不就得了,于是…
/**
* 黑人
* @author lenovo
*/
public class BlackHuman implements Human {
@Override
public void getColor() {
System.out.println("我是一个黑人,我的皮肤是黑色的");
}
@Override
public void talk() {
System.out.println("我是黑人,我说话谁都听不懂");
}
}
妈耶,这一下把女娲下的不轻,竟然造出来一个黑兄弟,难受。女娲决定再接再厉,吸取前两次的经验教训,这个好好把握火候
/**
* 黄种人
* @author lenovo
*/
public class YellowHuman implements Human {
@Override
public void getColor() {
System.out.println("我是一个黄种人,我的皮肤是黄色的");
}
@Override
public void talk() {
System.out.println("我是一个黄种人,我说中国话");
}
}
嘿嘿嘿,还是这黄种人看着舒服,说话也好听。最后女娲总结了一下造人的方法,准备批量生产。
AbstractHumanFactory是一个抽象类,定义了一个八卦炉具有的整体功能,HumanFactory为实现类,完成具体的任务——创建人类;Human接口是人类的总称,其三个实现类分别为三类人种;NvWa类是一个场景类,负责模拟这个场景,执行相关的任务。
我们定义的每个人种都有两个方法:getColor(获得人的皮肤颜色)和talk(交谈),
public static void main(String[] args) {
//声明阴阳八卦炉
AbstractHumanFactory yinyanglu = new HumanFactory();
//女娲第一次造人,火候不足,于是白人产生了
System.out.println("--造出的第一批人是白色人种--");
Human whiteHuman = yinyanglu.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
//女娲第二次造人,火候过足,于是黑人产生了
System.out.println("\n--造出的第二批人是黑色人种--");
Human blackHuman = yinyanglu.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
//第三次造人,火候刚刚好,于是黄色人种产生了
System.out.println("\n--造出的第三批人是黄色人种--");
Human yellowHuman = yinyanglu.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();
}
--造出的第一批人是白色人种--
我是一个白人,我的皮肤是白色的
我是一个白人,我说英语
--造出的第二批人是黑色人种--
我是一个黑人,我的皮肤是黑色的
我是黑人,我说话谁都听不懂
--造出的第三批人是黄色人种--
我是一个黄种人,我的皮肤是黄色的
我是一个黄种人,我说中国话
工厂模式的优点
-
良好的封装性,代码结构清晰,一个对象创建是由条件约束的。
-
工厂方法模式的扩展比较好,在增加产品类的情况下,只要适当的修改具体的工厂类或扩展一个工厂类。
-
屏蔽产品类,不需要关心产品类的具体逻辑和实现,只要接口不变。
-
实现解耦框架。
扩展
简单工厂模式
有所不同的是,去掉了AbstractHumanFactory抽象类,同时把createHuman方法设置为静态类型,简化了类的创建过程,变更的源码仅仅是HumanFactory和NvWa类。
运行结果没有发生变化,但是我们的类图变简单了,而且调用者也比较简单,该模式是工厂方法模式的弱化,因为简单,所以称为简单工厂模式(Simple Factory Pattern),也叫做静态工厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式
延迟初始化
何为延迟初始化?一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。
public class ProductFactory {
private static final Map<String,Product> prMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception{
Product product =null;
//如果Map中已经有这个对象
if(prMap.containsKey(type)){
product = prMap.get(type);
}else{
if(type.equals("Product1")){
product = new ConcreteProduct1();
}else{
product = new ConcreteProduct2();
}
//同时把对象放到缓存容器中
prMap.put(type,product);
}
return product;
}
}
通过定义一个Map容器,容纳所有产生的对象,如果在Map容器中已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。
延迟加载框架是可以扩展的,例如限制某一个产品类的最大实例化数量,可以通过判断Map中已有的对象数量来实现,这样的处理是非常有意义的,例如JDBC连接数据库,都会要求设置一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。
延迟加载还可以用在对象初始化比较复杂的情况下,例如硬件访问,涉及多方面的交
互,则可以通过延迟加载降低对象的产生和销毁带来的复杂性。