工厂方法(Factory Method)
意图: 定义一个创建对象的接口,但让子类决定实例化哪个类
UML图:
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
代码示例:
以下是一个简单的工厂方法模式示例,模拟了普通人和机器人的创建场景。
1. 产品接口 (Product Interface)
public interface IHuman {/*** 吃饭行为* 定义人类进食的基本行为*/void eat();}
2. 具体产品 (Concrete Products)
public class Human implements IHuman {/*** 人类姓名属性* 用于标识不同的人类个体*/private String name;/*** 构造方法,用于初始化人类对象* @param name 人类姓名*/public Human(String name) {this.name = name;}/*** 实现IHuman接口的eat方法* 输出当前人类对象正在吃饭的信息*/@Overridepublic void eat() {System.out.println(this.name + "在吃饭");}}public class Robot implements IHuman {/*** 机器人的名称*/private String name;/*** 构造方法,用于初始化机器人的名称** @param name 机器人的名称*/public Robot(String name) {this.name = name;}/*** 实现IHuman接口的eat方法* 机器人通过充电来模拟人类的进食行为*/@Overridepublic void eat() {System.out.println(this.name + "在充电");}}
3. 创建者抽象类 (Creator Abstract Class)
public interface IMethodFacotory {/*** 根据名称创建具体的人类对象* @param name 人类名称* @return 对应的人类对象实例*/IHuman createHuman(String name);
}
4. 具体创建者 (Concrete Creators)
public class HumanFacory implements IMethodFacotory{/*** 根据名称创建具体的人类对象* @param name 人类名称* @return 对应的人类对象实例*/public IHuman createHuman(String name) {return new Human( name);}
}
public class RobotFacory implements IMethodFacotory{/*** 根据名称创建机器人实例* @param name 机器人的名称* @return 返回一个新的Robot对象*/public IHuman createHuman(String name) {return new Robot( name);}
}
5. 客户端代码 (Client Code)
public class Test {public static void main(String[] args) {// 创建具体工厂 - 人类工厂IMethodFacotory humanFactory = new HumanFacory();// 创建具体产品 - 人类实例IHuman human = humanFactory.createHuman("张三");// 调用人类的吃饭行为human.eat();// 切换为机器人工厂IMethodFacotory robotFactory = new RobotFacory();// 创建具体产品 - 机器人实例IHuman robot = robotFactory.createHuman("机器人");// 调用机器人的吃饭行为robot.eat();}
}
在Spring框架中的应用
工厂方法模式在Spring中得到了极致的使用。最典型的例子就是BeanFactory
和ApplicationContext
接口。
BeanFactory
是Spring IoC容器的基础接口,其核心方法getBean(String name)
就是一个工厂方法。- 当你调用
ctx.getBean("myService")
时,容器会根据你的配置(XML、注解或Java Config)来决定是返回一个已经存在的单例Bean,还是创建一个新的原型Bean,或者是返回一个被代理包装后的Bean。具体的创建逻辑(即使用哪个具体的工厂)由Spring在启动时根据你的配置来决定和实现。
总结
工厂方法模式通过让子类决定创建的对象类型,来达到将对象创建的过程封装的目的,使得代码更加灵活和可扩展,符合“开闭原则”(对扩展开放,对修改关闭)。它是解耦框架代码的利器。