再说设计模式-工厂方法模式扩展
2019-01-31 本文已影响73人
oneape15
在上一篇文章我们介绍了《工厂方法模式》
其实,工厂方法模式有很多扩展,而且与其他模式结合使用威力更大,在这一章我们大致介绍四种扩展。
一、缩小为简单工厂模式
有时候,一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法就可以了,我们这里以女娲造人的故事为蓝本,设计出类图如下:
简单工厂模式类图
// 简单工厂模式中的工厂类
public class HumanFactory {
public static <T extends Human> createHuman(Class<T> c) {
Human human = null;
try {
human = (Human)Class.forName(c.getName()).newInstance();
} catch(Exception e) {
System.out.println("人种生成错误!");
}
return (T)human;
}
}
// 简单工厂模式中的场景类
public class NvWa {
public static void main(String[] args) {
// 第一次造人,火候未到,所以白种人出来了
Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
// 第二次造人,火候过了,所以黑种人出来了
Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
// 第三次造人,火候刚好,所以黄种人出来了
Human yellowHuman = HumanFactory.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();
}
}
该模式是工厂方法模式的弱化,因为简单,所以称为简单工厂模式(Simple Factory Patttern)
,也叫做静态工厂模式。其缺点:工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。
二、升级为多个工厂类
当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗时费力的情况,所以每个产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。
所以,考虑到需要结构清晰,我们就为每个产品定义一个创造者,然后由调用者自己去选择与哪个工厂方法关联。类图如下:
在复杂的应用中一般采用多工厂的方法,然后再增加一个
协调类
,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。
三、替代单例模式
// 单例类
public class Singleton {
// 不允许通过new产生一个对象
private Singleton() {
}
public void doSomething() {
// 业务处理
}
}
// 单例工厂类
public class SingletonFactory {
private static Singleton singleton;
static {
try {
Class clazz = Class.forName(Singleton.class.getName());
// 获得无参构造
Constructor constructor = clazz.getDeclaredConstructor();
// 设置无参构造是可访问的
constructor.setAccessible(true);
// 产生一个实例对象
singleton = (Singleton)constructor.newInstance();
} catch (Exception e) {
// 异常处理
}
}
public static Singleton getSingleton() {
return singleton;
}
}
类图如下:
工厂方法模式替代单例模式类图
这个通过反射的方式建立一个单例对象,虽然有点取巧,其他地方也可以通过这种方式来构建单例对象。
四、延迟初始化
何为延迟初始化(Lazy initialization) ? 一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。延迟初始化是工厂方法模式的一个扩展应用,其通用类图如下:
延迟初始化的通用类图
ProductFactory负责产品类对象的创建工作,并且通过prMap变量产生一个缓存,对需要再次被重用的对象保留。
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中已有的对象数量来实现,这样的处理是非常有意义的,例如JDBC连接数据库,都会要求设置一个MaxConnections最大连接数量,该数量就是内存中最大实例化的数量。