简单工厂模式(Simple Factory Pattern)又叫静态工厂方法模式(Static FactoryMethod Pattern)。专门定义一个类来负责创建其它类的实例,由它来决定实例化哪个具体类,从而避免了在客户端代码中显式指定,实现了解耦。该类由于可以创建同一抽象类(或接口)下的不同子类对象,就像一个工厂一样,因此被称为工厂类。
如图,我们设计一个简单的运算器来解释该模式。
简单工厂类:
public class OptionerFactory {
public static Optioner createOptioner(String opt) {
Optioner optioner = null;
switch (opt) {
case "+":
optioner = new AddOptioner();
break;
case "-":
optioner = new SubOptioner();
break;
case "*":
optioner = new MulOptioner();
break;
case "/":
optioner = new DivOptioner();
break;
}
return optioner;
}
}
- Factory:简单工厂模式的核心,负责实现创建所有实例的内部逻辑。Fcatory 类可以被外界直接调用,创建所需的产品对象。
运算类:
public class Optioner {
private int oNumFirst;//第一个数
private int oNumSecond;//第二个数
public int getoNumFirst() {
return oNumFirst;
}
public void setoNumFirst(int oNumFirst) {
this.oNumFirst = oNumFirst;
}
public int getoNumSecond() {
return oNumSecond;
}
public void setoNumSecond(int oNumSecond) {
this.oNumSecond = oNumSecond;
}
public Optioner() {
}
public Optioner(int oNumFirst, int oNumSecond) {
this.oNumFirst = oNumFirst;
this.oNumSecond = oNumSecond;
}
public int getReuslt() {
return 0;
}
}
- Product:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体运算类:
/**
* 加法运算
*/
public class AddOptioner extends Optioner {
@Override
public int getReuslt() {
return getoNumFirst() + getoNumSecond();
}
}
/**
* 减法运算
*/
public class SubOptioner extends Optioner {
@Override
public int getReuslt() {
return getoNumFirst() - getoNumSecond();
}
}
/**
* 乘法运算
*/
public class MulOptioner extends Optioner {
@Override
public int getReuslt() {
return getoNumFirst() * getoNumSecond();
}
}
/**
* 除法运算
*/
public class DivOptioner extends Optioner {
@Override
public int getReuslt() {
if (getoNumSecond() == 0) {
System.out.println("除数不能为0");
return -1;
} else {
return getoNumFirst() / getoNumSecond();
}
}
}
- Concrete Product:简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
开—闭原则:是说软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。
功能的扩展体现在引进新的产品上,开—闭原则要求新的产品加入系统时,无需对现有代码进行修改。在简单工厂模式中,这点对于产品角色是成立的,而对于工厂角色是不成立的。产品角色无需修改就课接纳新的产品。
但对于工厂角色来说,增加新产品要修改程序;工厂角色必须知道每一种产品,如何创建它们,以及何时向客户端提供它们。所以,简单工厂角色只在有限的程度上支持开—闭原则。
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类。对客户端来说,去除了与具体产品的依赖。
问题是增加功能,就要改变简单工厂类并且不满足开闭原则。
进而引出工厂方法模式。工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫多态工厂模式或者虚拟构造器模式。在工厂方法模式中,工厂父类定义创建产品对象的公共接口,具体的工厂子类负责创建具体的产品对象。每一个工厂子类负责创建一种具体产品。
如图:
和简单工厂模式直接使用静态工厂方法创建产品对象不同,在工厂方法,客户端通过实例化具体的工厂类,并调用其创建实例接口创建具体产品类的实例。根据依赖倒置原则,具体工厂类的实例由工厂接口引用(客户端依赖于抽象工厂而非具体工厂),具体产品的实例由产品接口引用(客户端和工厂依赖于抽象产品而非具体产品)。
接下来,画一下类图:
我们所需要做的:
简单工厂 →加Operation子类
→改工厂类(case)
工厂方法 →加Operation子类
→加工厂子类
→修改客户端
这样整个工厂和产品体系其实都没有修改的变化,而只是扩展的变化,完全符合开闭原则,从这个角度讲优于简单工厂模式。
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在,也就是说,工厂方法把简单工厂的内部逻辑判断移到客户端代码进行。想要增加功能,本来是改工厂类,而现在是修改客户端。
工厂方法模式是简单工厂模式的进一步抽象和推广。它克服了简单工厂违背开闭原则的缺点,又保持了封装对象创建过程的优点,使得更换对象时,不需要做大的改动,降低了客户程序与产品对象的耦合。
但是由于每加一个产品,就需要加一个产品工厂的类,增加了额外的工作量。而且无法避免修改客户端的代码。
当然,我们可以通过反射→避免分支判断问题。后面补充。