工厂方法模式
归纳编程学习的感悟,
记录奋斗路上的点滴,
希望能帮到一样刻苦的你!
如有不足欢迎指正!
共同学习交流!
🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言📝
把命运掌握在自己手中!
一起加油!
记录奋斗路上的点滴,
希望能帮到一样刻苦的你!
如有不足欢迎指正!
共同学习交流!
🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言📝
把命运掌握在自己手中!
一起加油!
工厂方法模式
在面向对象编程中,工厂方法模式(Factory Method Pattern) 是一种经典的创建型设计模式。它通过定义一个用于创建对象的接口,但让子类决定实例化哪一个类,从而将对象的创建延迟到子类中。本篇博客将结合一个具体的案例——电视机工厂系统,深入讲解工厂方法模式的结构、实现要点、优缺点,并完整展示如何在 Java 中实现该模式。
一、任务背景
假设我们有一个电视机生产系统,最初只有一个工厂负责生产所有品牌的电视机。但随着业务扩展,我们需要支持海尔、海信、TCL、创维等多个品牌,并希望在新增品牌时无需修改原有代码,以提高系统的灵活性和可扩展性。
这时,工厂方法模式就派上了用场。
二、工厂方法模式的角色
工厂方法模式包含以下四个核心角色:
角色 | 说明 |
---|---|
Product(抽象产品) | 定义产品的接口,所有具体产品都必须实现该接口。例如 TV 接口。 |
ConcreteProduct(具体产品) | 实现抽象产品接口的具体类。如 HaierTV 、HisenseTV 。 |
Factory(抽象工厂) | 声明工厂方法,该方法返回一个 Product 类型的对象。如 TVFactory 接口。 |
ConcreteFactory(具体工厂) | 实现工厂方法,负责创建具体产品对象。如 HaierTVFactory 、HisenseTVFactory 。 |
三、实现要点
- 统一产品接口
所有产品(电视机)必须实现同一个接口(TV
),确保客户端代码可以以统一方式使用不同品牌的产品。 - 抽象工厂接口
定义一个工厂接口(TVFactory
),声明创建产品的方法(produceTV()
)。 - 具体工厂实现
每个品牌对应一个具体工厂类,重写工厂方法,返回对应品牌的产品实例。 - 配置驱动创建
通过配置文件(如 XML)动态指定要使用的工厂类,实现运行时解耦。
四、代码实现
1. 抽象产品接口:TV.java
package step3;public interface TV {void play();
}
2. 具体产品类
// HaierTV.java
package step3;public class HaierTV implements TV {@Overridepublic void play() {System.out.println("海尔电视机播放中......");}
}// HisenseTV.java
package step3;public class HisenseTV implements TV {@Overridepublic void play() {System.out.println("海信电视机播放中......");}
}
3. 抽象工厂接口:TVFactory.java
package step3;public interface TVFactory {TV produceTV();
}
4. 具体工厂类(填空部分)
// HaierTVFactory.java
package step3;public class HaierTVFactory implements TVFactory {@Overridepublic TV produceTV() {return new HaierTV(); // ← 填空处}
}// HisenseTVFactory.java
package step3;public class HisenseTVFactory implements TVFactory {@Overridepublic TV produceTV() {return new HisenseTV(); // ← 填空处}
}
5. 配置文件读取工具:XMLUtil.java
package step3;import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;public class XMLUtil {public static Object getBean() {try {DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc = builder.parse(new File("./src/FactoryMethodconfig.xml"));NodeList nl = doc.getElementsByTagName("className");Node classNode = nl.item(0).getFirstChild();String cName = classNode.getNodeValue();Class<?> c = Class.forName(cName);return c.newInstance();} catch (Exception e) {e.printStackTrace();return null;}}
}
6. 客户端代码:Client.java
package step3;public class Client {public static void main(String args[]) {try {TV tv;TVFactory factory;factory = (TVFactory) XMLUtil.getBean(); // 从配置文件读取工厂类tv = factory.produceTV();tv.play();} catch (Exception e) {System.out.println(e.getMessage());}}
}
7. 配置文件示例:FactoryMethodconfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<config><className>step3.HaierTVFactory</className>
</config>
若想切换为海信电视,只需将
<className>
改为step3.HisenseTVFactory
,无需修改任何 Java 代码!
五、工厂方法模式的缺点
尽管工厂方法模式带来了良好的扩展性,但也存在一些不足:
- 类数量成对增加:每新增一个产品,就需要新增一个对应的工厂类,系统复杂度上升。
- 抽象层次加深:对初学者而言,理解多个抽象层和间接调用可能有一定难度。
- 配置管理成本:依赖外部配置(如 XML)虽然灵活,但也增加了部署和维护的复杂性。
六、总结
通过本案例可以看出,工厂方法模式完美解决了“在不修改现有代码的前提下扩展新产品”的问题,符合开闭原则(对扩展开放,对修改关闭)。
当你需要:
- 支持多种产品变体;
- 将对象创建逻辑与使用逻辑分离;
- 通过配置动态切换实现类;
那么,工厂方法模式是一个非常合适的选择。
💡 扩展思考:如果产品种类非常多(如上百种电视品牌),可以考虑结合反射 + 注解或使用Spring 的 BeanFactory来进一步简化工厂类的编写。
设计模式不是银弹,而是工具。合理使用,方能事半功倍。