一、概念
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,提供了一种创建对象的最佳方式。它通过定义一个创建对象的接口,但由子类决定实例化哪一个类,从而使得系统在不具体指定对象的类型的情况下工作
二、原理
(一)定义
工厂方法模式定义一个用于创建对象的接口,这个接口被称为工厂方法。通过这个方法,子类可以决定实例化哪一个类。它将对象的创建过程封装起来,使得客户端代码不需要了解具体的创建逻辑,只需要关注对象的使用。
(二)实现原理
工厂方法模式主要包含以下角色: 1)抽象产品角色(Product):定义产品的规范,描述产品的主要特性和行为。 2)具体产品角色(ConcreteProduct):实现抽象产品角色所定义的接口,由工厂角色创建。 3)抽象工厂角色(Creator):声明了工厂方法,用于返回一个产品对象。 4)具体工厂角色(ConcreteCreator):实现了抽象工厂中的工厂方法,返回一个具体产品对象。
实现时,客户端代码指向抽象工厂和抽象产品,具体工厂和具体产品类需要在运行时决定创建哪一个具体产品类。
(三)优点
封装性好,代码结构清晰,用户可以完全不了解对象的创建过程,只需要关心产品的使用。
扩展性强,在增加新的产品时,无须修改原有系统的代码,符合开闭原则。
使得系统易于将产品的创建和使用分离,使得系统更加灵活。
(四)缺点
每一个具体产品对应一个具体工厂类,会导致类的个数增加,增加了系统的复杂性。
使用工厂方法模式会在系统中引入更多的抽象层,可能会给开发人员的理解和开发带来一定的困难
三、用途
工厂方法模式适用于以下场景: 1)创建对象的逻辑复杂,将这些逻辑封装在一个单独的工厂方法中可以避免代码重复,并隐藏复杂的实现细节。 2)产品类有多个等级结构,工厂方法可以在不同层次中使用,每个具体工厂负责创建特定的产品对象。 3)系统中产品类的种类经常变化,但客户端仍然使用相同的接口,工厂方法模式可以很容易地新增新的具体产品类而不需要修改现有代码。 4)解耦框架与实现,工厂方法可以在一个框架中用来封装和隔离具体实现,客户端代码可以通过工厂接口与具体实现解耦
四、如何实现
以下是工厂方法模式的基本实现步骤:
(一)定义抽象产品
定义一个产品接口,声明所有由创建者及其子类构建的对象的通用接口。
public interface Product {
void operate();
}
(二)创建具体产品类
实现抽象产品接口,每个具体产品类都有不同的实现方式。
public class ConcreteProductA implements Product {
@Override
public void operate() {
System.out.println("ConcreteProductA is operating.");
}
}
public class ConcreteProductB implements Product {
@Override
public void operate() {
System.out.println("ConcreteProductB is operating.");
}
}
(三)定义抽象工厂
定义一个创建者类,声明返回产品对象的工厂方法,该方法的返回对象类型必须与产品接口相匹配。
public abstract class Creator {
public abstract Product factoryMethod();
}
(四)创建具体创建者类
重写基础工厂方法,使其返回不同类型的产品。
public class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
public class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}
(五)使用示例
public class Client {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.factoryMethod();
productA.operate();
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.operate();
}
}
五、框架应用
工厂方法模式在 Java 框架中得到了广泛应用,例如:
(一)Spring 框架
Spring 框架中广泛使用了工厂模式,其中最著名的应用就是 BeanFactory 和 ApplicationContext。这些容器负责实例化、配置和组装 Bean,这是工厂方法模式的一个典型应用。
示例代码
// 定义一个接口
public interface MyBean {
void execute();
}
// 实现接口的类
public class MyBeanImpl implements MyBean {
@Override
public void execute() {
System.out.println("MyBeanImpl executing...");
}
}
// 配置文件(applicationContext.xml)中配置 Bean
<beans>
<bean id="myBean" class="com.example.MyBeanImpl"/>
</beans>
// 使用 Spring 容器获取 Bean 实例
public class SpringDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = context.getBean("myBean", MyBean.class);
myBean.execute();
}
}
(二)Apache Commons Pool
Apache Commons Pool 是一个提供了通用对象池实现的库。在对象池中,工厂模式被用来创建和管理对象实例。
示例代码
// 定义一个对象池工厂
public class MyObjectPoolFactory extends BasePoolableObjectFactory<MyObject> {
@Override
public MyObject makeObject() throws Exception {
return new MyObject();
}
// 其他方法(如 activateObject、passivateObject、destroyObject 等)可以重写...
}
// 使用对象池
public class ObjectPoolDemo {
public static void main(String[] args) throws Exception {
GenericObjectPool<MyObject> pool = new GenericObjectPool<>(new MyObjectPoolFactory());
MyObject obj = pool.borrowObject();
// 使用 obj
pool.returnObject(obj);
}
}
六、案例及实现代码
以下是一个生成跨平台的 GUI 元素的案例:
// Button.java: 通用产品接口
public interface Button {
void render();
void onClick();
}
// HtmlButton.java: 具体产品
public class HtmlButton implements Button {
public void render() {
System.out.println("<button>Test Button</button>");
onClick();
}
public void onClick() {
System.out.println("Click! Button says - 'Hello World!'");
}
}
// WindowsButton.java: 另一个具体产品
public class WindowsButton implements Button {
public void render() {
System.out.println("[Windows Look] Test Button");
onClick();
}
public void onClick() {
System.out.println("Click! Button says - 'Hello Windows!'");
}
}
// GUIFactory.java: 抽象创建者
public abstract class GUIFactory {
public abstract Button createButton();
}
// HtmlGUIFactory.java: 具体创建者
public class HtmlGUIFactory extends GUIFactory {
@Override
public Button createButton() {
return new HtmlButton();
}
}
// WindowsGUIFactory.java: 具体创建者
public class WindowsGUIFactory extends GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
}
// 使用示例
public class Demo {
public static void main(String[] args) {
GUIFactory factory;
Button button;
// 使用 HTML GUI 工厂
factory = new HtmlGUIFactory();
button = factory.createButton();
button.render();
// 使用 Windows GUI 工厂
factory = new WindowsGUIFactory();
button = factory.createButton();
button.render();
}
}
七、应用场景
工厂方法模式适用于以下场景:
1)当系统需要引入新的产品时,不需要修改已有的代码,只需要添加新的代码即可,从而增强了系统的可扩展性和可维护性。
2)当创建一个对象的决策需要考虑多个因素时,将这些逻辑封装在一个单独的工厂方法中可以避免代码重复,并隐藏复杂的实现细节。
3)当产品类有多个等级结构时,工厂方法可以在不同层次中使用,每个具体工厂负责创建特定的产品对象。
4)当系统中产品类的种类经常变化,但客户端仍然使用相同的接口时,工厂方法模式可以很容易地新增新的具体产品类而不需要修改现有代码。
八、总结
工厂方法模式通过将对象的创建过程封装到子类中,使得系统在不具体指定对象的类型的情况下工作,增加了程序的灵活性和扩展性,同时隐藏了具体类的实现细节,减少了客户端与具体类之间的依赖。它符合依赖倒置原则,使得代码结构更加合理和易于维护。