定义
设计一个工厂类,给工厂类中创建产品实例的方法传入参数来决定创建哪一种产品类的实例。
简单工厂模式是属于创建型模式,又叫做静态工厂方法模式。
类型
创建型
角色
- 工厂角色:工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它的返回类型为抽象产品类型Product
- 抽象产品角色:它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
- 具体产品角色:它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法
在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象,它是工厂模式家族中最简单的一员
示例
我们使用简单工厂模式来设计一个计算器的后台代码
首先定义一个抽象类
public abstract class Calculate {
double numA;
double numB;
public Calculate(){
}
public Calculate(double numA,double numB){
this.numA = numA;
this.numB = numB;
}
public abstract double cal();
}
实现重写计算类方法的乘法子类和加法子类
public class CalculateMultiply extends Calculate{
public CalculateMultiply(double numA, double numB){
super();
this.numA=numA;
this.numB=numB;
}
@Override
public double cal() {
return numA*numB;
}
}
public class CalculateAdd extends Calculate{
public CalculateAdd(double numA,double numB){
super();
this.numA=numA;
this.numB = numB;
}
@Override
public double cal() {
return numA+numB;
}
}
业务实现的应用层直接运用java语言的多态
但是应用层代码太依赖对应的类。高层模块(应用层)不应该依赖低层模块,违背了依赖倒置原则。
设计模式七大原则
public static void main(String[] args){
Calculate calculate = new CalculateAdd(1,3);
calculate.cal();
}
所以增加一个第三方来管理,也就工厂类
但是如下的方式,只要工厂增加了新产品,就要修改工厂类,违反了开闭原则。并且还会带来大量的if-else语句。
public class CalculateFactory {
public Calculate getCalculate(String type){
if(type=="CalculateAdd"){
return new CalculateAdd();
}else if(type =="CalculateMultiply"){
return new CalculateMultiply();
}
return null;
}
}
应用层业务代码
public static void main(String[] args){
CalculateFactory calculateFactory = new CalculateFactory();
Calculate calculate = calculateFactory.getCalculate("CalculateAdd");
if(calculate == null){
System.out.printf("没能创建成功\n");
}else{
calculate.setNumA(1);
calculate.setNumB(3);
System.out.printf("计算结果为:%f\n",calculate.cal());
}
}
所以工厂可以采用反射方式实现创建不同的实例(这样添加新产品时就不需要修改工厂类)
package com.xt.designmode.creational.simplefactory;
public class CalculateFactory {
public Calculate getCalculate(Class c){
Calculate calculate = null;
try{
Class <?> cls = Class.forName(c.getName()) ;
#调用无参构造
calculate = (Calculate) cls.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return calculate;
}
}
写业务的应用层使用反射
public class Test {
public static void main(String[] args){
CalculateFactory calculateFactory = new CalculateFactory();
Calculate calculate = calculateFactory.getCalculate(CalculateMultiply.class);
if(calculate == null){
System.out.printf("没能创建成功\n");
}else{
calculate.setNumA(1);
calculate.setNumB(3);
System.out.printf("计算结果为:%f\n",calculate.cal());
}
}
}
简单工厂模式总结
主要优点如下:
- 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
主要缺点如下:
- 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护,且违背开闭原则。(就算使用反射,避免创建不同产品实例时代码的修改,但是有时候工厂可能不仅仅要实例化具体的产品对象,还有其他操作,因此引入工厂方法模式)
适用场景:
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
应用:
- Calendar 类获取日历类对象
- JDBC 获取数据库连接
- LoggerFactory 获取 Logger 对象
参考:https://blog.csdn.net/wwwdc1012/article/details/82504040