工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
一、简单工厂模式
由一个工厂对象决定创建一种产品类的实例,即定义一个创建对象的类,由这个类来封装实例化对象的行为。
使用场景:
当需要大量创建某种、某类或某批对象时。
public abstract Operation{
public abstract getResult(double a,double b);
}
public class OperationFactory{
public static Operation createOperation(String operate){
Operation op=null;
switch(operate){
case "+":
case "-":
case "*":
case "/":
}
return op;
}
}
优点:
① 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,它提供了专门的工厂类用于创建对象。
② 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类 所对应的参数 即可。
③ 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
① 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
② 会增加系统中类的个数,增加了系统的复杂度和理解难度。
③ 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,同样违背了了“开闭原则”;在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
④ 使用了 静态工厂方法 ,造成工厂角色无法形成基于继承的等级结构。
二、工厂方法模式
工厂方法模式: 定义一个用于创建对象的接接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到其子类。
结构图:
工厂方法模式将简单工厂模式中的 case逻辑判断 移到了客户端代码。
//运算抽象类
public abstract class Operation{
public abstract double getResult(double a,double b);
}
//工厂接口
public interface IFactory{
Operation createOperation();
}
//加法工厂
class AddFactory implements IFactory{
Operation createOperation(){
return new AddOperation();
};
}
//减法工厂
class SubFactory implements IFactory{
Operation createOperation(){
return new SubOperation();
};
}
总结:
工厂方法模式就是用 工厂类 来创建 产品类 ,而这个工厂类和产品类均继承自某个抽象类或接口。
优点:
对于功能的扩展不会违背 开放封闭原则 ,复用性较高。
三、抽象工厂模式
抽象工厂模式: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
优点:
将工厂方法模式的工厂与产品的 一对一 关系变为 一对多 的关系,使得一个工厂能创建一个产品的多个实现类的实例。
缺点:
由于可能封装了大量对象和工厂创建,新加产品需要大批量地修改已定义好的工厂相关的类,因此对于产品和工厂的扩展不太友好。
四、反射+配置文件
为解决工厂方法在修改和扩展功能时的问题:
使用反射机制: 通过传入的 类名(字符串形式) 来判断实例化哪一个子类,而不需要像简单工厂模式一样在switch-case语句中判断;
使用配置文件: 可以不必在原有类中修改反射创建实例时传入的字符串参数,而只需要在配置文件中修改即可,避免了在程序中多处修改的繁琐工作,有效地遵循了开放封闭原则。
public class DataFactory {
private static final String db="DB";
private static final Properties properties=new Properties();
public DataFactory() {
FileInputStream fin;
URL url=getClass().getResource("config.propertise");
try {
fin = new FileInputStream(new File(url.toURI()));
properties.load(fin);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
private static IUser createUser() throws InstantiationException, IllegalAccessException {
Class<?> clazz = null;
try {
clazz = Class.forName(properties.getProperty(db)+"User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (IUser) clazz.newInstance();
}
private static IDepartment createDepartment() throws InstantiationException, IllegalAccessException {
Class<?> clazz = null;
try {
clazz = Class.forName(properties.getProperty(db)+"Department");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (IDepartment) clazz.newInstance();
}
总结
三种工厂模式有各自的应用场景,实际应用时能解决问题满足需求即可,可灵活变通,无所谓高级与低级。