二十三种设计模式解读——什么是工厂方法模式
author:陈镇坤27
日期:2022年2月10日
修改日期:2022年6月23日
——————————————————————————————
一、工厂方法模式
1、定义
Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses
定义一个(工厂)接口以创建实例,由(工厂)子类决定实例化哪个类。工厂方法模式将一个类的实例延迟到(工厂)子类中。
简单来说,工厂方法模式将创建对象的过程集中到了“工厂”类当中。
这样有什么好处?
许多散户织出来的100匹布料和一个工厂织出来的100匹布料有什么差别?
散户的个性很强。而工厂的集约化程度高!
这也就是工厂方法模式的特点。
2、应用场景
全局创建、统一配置等场景可以使用。例如线程池,数据库池。
3、通用范本
一般构造为:一个抽象类,抽象需要创建对象的共性或约束的产品类;抽象产品类的子类;一个抽象类,抽象工厂动作;抽象工厂类的子类。
使用时,实例化抽象工厂类,通过抽象工厂类创建产品。
4、示例讲解
有画画的需求,既又现代画派,也有印象画派。以后还可能增加一些新的画派。
现在要求对所有的画作都在画画时加上相同的logo。
在没使用工厂方法模式的时候,我们只能一个个去找对应的实例。
如果使用了工厂方法模式,则由工厂方法统一创建对象,便可以在这个创建对象的环节做统一的处理。
PS:工厂方法的代码还是贴出来比较好
@Override
public <T extends AbstractDraw> T createDraw(Class<T> c) {
T t = null;
try {
// 全限定名获取Class对象并实例化(泛型无法用new关键字实例)
t = (T)Class.forName(c.getName()).newInstance();
// 希望统一处理
t.setName("小明");
} catch (Exception e) {
e.printStackTrace();
}
// T t = (T)c.forName(c.getName()).newInstance();
return t;
}
5、拓展
1)多个工厂
这个也比较好解释,用工厂创建具体对象的目的是为了能够对对象初始化等过程进行集约管理。例如设置特定的属性等等。
假如产品有多个,每个都有不同的初始化情况,那工厂方法中的判断就会越来越冗长,不利于维护。
所以此时不如一个工厂对应一个具体的子类。这非常符合单一职责的原则,代码也更简约清晰。
唯一的不足就是,新增一个产品,就要新增一个工厂。
当然,这也有其他优化方案——封装一个获取特定工厂的工具类。
2)简单工厂
很容易理解,简单之处在于把工厂的抽象类给简化掉了,工厂类的工厂方法用static修饰。这种用法使用起来简单快捷,缺点是工厂方法没有抽象类来约束以得到良好的扩展性,不符合开闭原则(原因可具体看我之前写的开闭原则篇章)。
3)工厂实现单例
对要实现单例的目标进行构造器私有化,随后作为聚合对象,通过反射的方式在工厂实例化。
public class SingletonFactory {
private static Singleton singleton = null;
static {
try {
// 反射创建对象
// ps:使用newInstance要求该类有默认的公共无参构造器
// singleton = Singleton.class.newInstance();
Class<Singleton> singletonClass = Singleton.class;
Constructor<Singleton> declaredConstructor = singletonClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
singleton = declaredConstructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Singleton getSingleton(){
return singleton;
}
}
4)工厂延迟初始化
延迟初始化的目的是为了提高对象的可重用性,减少不必要的资源开销。
唯一需要注意的是,存储在工厂缓存map中的对象的纯洁性(可能被外部引用修改)
这种设计模式,可以控制工厂创建对象的数量。可以应用在连接池场景中。
/**
* @Author: jkun
* @Description:缓存实例
*
* “延迟加载还可以用在对象初始化比较复杂的情况下,
* 例如硬件访问,涉及多方面的交互,
* 则可以通过延迟加载降低对象的产生和销毁带来的复杂性。”
* @Date: Create in 14:21 2022/2/10
*/
public class DrawFactory extends AbstractDrawFactory {
private static final Map<String,AbstractDraw> map = new HashMap<>();
@Override
public <T extends AbstractDraw> T createDraw(Class<T> c) {
T t = null;
try {
if (map.containsKey(c.getSimpleName())) {
t = (T)map.get(c.getSimpleName());
}
else {
t = (T)Class.forName(c.getName()).newInstance();
t.setName("小明");
map.put(c.getSimpleName(),t);
}
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
}
(2022-6-23)
6、总结
工厂制作产品,可以对产品做集约化处理。