• 设计模式之工厂模式


    工厂模式是一种创建型设计模式,其核心思想是定义一个创建对象的接口(即工厂),让子类决定实例化哪一个类。工厂模式将对象的创建与使用分离,使代码更易于维护和扩展,尤其在需要根据条件动态创建不同类的实例时非常有用。

    工厂模式主要有以下三种形态:

    简单工厂模式(Simple Factory)

    工厂方法模式(Factory Method)

    抽象工厂模式(Abstract Factory)

    1、简单工厂模式(Simple Factory)

    • 概念:定义一个工厂类,负责创建某一类对象,客户端通过调用工厂类的静态方法来获取所需对象。简单工厂模式封装了对象的创建过程,隐藏了具体产品的类名,使得客户只需关注产品的接口而非创建细节。
    • 优点:减少客户端与具体产品类之间的耦合,新增产品时只需修改工厂类即可。
    • 缺点:当产品种类较多时,工厂类可能会变得庞大且难以维护;违背开闭原则,增加新产品时需要修改工厂类代码。

    Java代码示例:

    1. // 定义产品接口
    2. public interface Product {
    3. void use();
    4. }
    5. // 具体产品A
    6. public class ConcreteProductA implements Product {
    7. @Override
    8. public void use() {
    9. System.out.println("Using product A");
    10. }
    11. }
    12. // 具体产品B
    13. public class ConcreteProductB implements Product {
    14. @Override
    15. public void use() {
    16. System.out.println("Using product B");
    17. }
    18. }
    19. // 工厂类
    20. public class SimpleFactory {
    21. public static Product createProduct(String type) {
    22. if ("A".equals(type)) {
    23. return new ConcreteProductA();
    24. } else if ("B".equals(type)) {
    25. return new ConcreteProductB();
    26. } else {
    27. throw new IllegalArgumentException("Invalid product type");
    28. }
    29. }
    30. }
    31. // 客户端代码
    32. public class Client {
    33. public static void main(String[] args) {
    34. Product productA = SimpleFactory.createProduct("A");
    35. productA.use(); // 输出:Using product A
    36. Product productB = SimpleFactory.createProduct("B");
    37. productB.use(); // 输出:Using product B
    38. }
    39. }

    2、工厂方法模式(Factory Method)

    • 概念:定义一个用于创建对象的抽象工厂接口(或抽象类),并让子类决定实例化哪一个产品类。工厂方法模式将简单工厂的静态方法改为抽象方法,让子类去实现具体的对象创建。
    • 优点:符合开闭原则,新增产品时只需增加新的工厂子类,无需修改原有代码;支持多态,子类可以覆盖基类的方法以提供不同类型的对象。
    • 缺点:类的层级结构可能会变得复杂,特别是产品类型较多时。

    Java代码示例:

    1. // 定义产品接口
    2. public interface Product {
    3. void use();
    4. }
    5. // 具体产品A
    6. public class ConcreteProductA implements Product {
    7. @Override
    8. public void use() {
    9. System.out.println("Using product A");
    10. }
    11. }
    12. // 具体产品B
    13. public class ConcreteProductB implements Product {
    14. @Override
    15. public void use() {
    16. System.out.println("Using product B");
    17. }
    18. }
    19. // 抽象工厂接口
    20. public interface Factory {
    21. Product createProduct();
    22. }
    23. // 具体工厂A
    24. public class ConcreteFactoryA implements Factory {
    25. @Override
    26. public Product createProduct() {
    27. return new ConcreteProductA();
    28. }
    29. }
    30. // 具体工厂B
    31. public class ConcreteFactoryB implements Factory {
    32. @Override
    33. public Product createProduct() {
    34. return new ConcreteProductB();
    35. }
    36. }
    37. // 客户端代码
    38. public class Client {
    39. public static void main(String[] args) {
    40. Factory factoryA = new ConcreteFactoryA();
    41. Product productA = factoryA.createProduct();
    42. productA.use(); // 输出:Using product A
    43. Factory factoryB = new ConcreteFactoryB();
    44. Product productB = factoryB.createProduct();
    45. productB.use(); // 输出:Using product B
    46. }
    47. }

    3、抽象工厂模式(Abstract Factory)

    • 概念:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式为创建一组产品族提供了一个接口,而具体的产品族创建由具体工厂子类实现。
    • 优点:隔离了具体产品类的使用,使得客户端只需与抽象产品和抽象工厂交互;支持产品族的切换,只需改变具体工厂的实例即可。
    • 缺点:增加了系统的复杂性,尤其是产品族中产品类数量较多时;新增产品族时需要修改抽象工厂接口及其实现类。

    Java代码示例:

    1. // 定义产品接口
    2. public interface ProductA {
    3. void useA();
    4. }
    5. public interface ProductB {
    6. void useB();
    7. }
    8. // 具体产品A1
    9. public class ConcreteProductA1 implements ProductA {
    10. @Override
    11. public void useA() {
    12. System.out.println("Using product A1");
    13. }
    14. }
    15. // 具体产品B1
    16. public class ConcreteProductB1 implements ProductB {
    17. @Override
    18. public void useB() {
    19. System.out.println("Using product B1");
    20. }
    21. }
    22. // 具体产品A2
    23. public class ConcreteProductA2 implements ProductA {
    24. @Override
    25. public void useA() {
    26. System.out.println("Using product A2");
    27. }
    28. }
    29. // 具体产品B2
    30. public class ConcreteProductB2 implements ProductB {
    31. @Override
    32. public void useB() {
    33. System.out.println("Using product B2");
    34. }
    35. }
    36. // 抽象工厂接口
    37. public interface AbstractFactory {
    38. ProductA createProductA();
    39. ProductB createProductB();
    40. }
    41. // 具体工厂1
    42. public class ConcreteFactory1 implements AbstractFactory {
    43. @Override
    44. public ProductA createProductA() {
    45. return new ConcreteProductA1();
    46. }
    47. @Override
    48. public ProductB createProductB() {
    49. return new ConcreteProductB1();
    50. }
    51. }
    52. // 具体工厂2
    53. public class ConcreteFactory2 implements AbstractFactory {
    54. @Override
    55. public ProductA createProductA() {
    56. return new ConcreteProductA2();
    57. }
    58. @Override
    59. public ProductB createProductB() {
    60. return new ConcreteProductB2();
    61. }
    62. }
    63. // 客户端代码
    64. public class Client {
    65. public static void main(String[] args) {
    66. AbstractFactory factory1 = new ConcreteFactory1();
    67. ProductA productA1 = factory1.createProductA();
    68. productA1.useA(); // 输出:Using product A1
    69. ProductB productB1 = factory1.createProductB();
    70. productB1.useB(); // 输出:Using product B1
    71. AbstractFactory factory2 = new ConcreteFactory2();
    72. ProductA productA2 = factory2.createProductA();
    73. productA2.useA(); // 输出:Using product A2
    74. ProductB productB2 = factory2.createProductB();
    75. productB2.useB(); // 输出:Using product B2
    76. }
    77. }

    使用中需要注意的问题:

    1. 明确工厂职责

      • 确保工厂类或方法专注于对象创建,避免承担过多业务逻辑,保持其单一职责。如果工厂过于复杂,可能需要进一步抽象或拆分为多个工厂。
      • 对于工厂方法模式和抽象工厂模式,要清晰划分工厂接口与具体工厂类的责任,确保接口的通用性和具体工厂类的可扩展性。
    2. 遵守开闭原则

      • 工厂模式的设计应遵循开闭原则,即对扩展开放,对修改关闭。新增产品时,应通过增加新的工厂类(工厂方法模式)或新的具体工厂子类(抽象工厂模式),而不是修改已有工厂类的代码。
      • 对于简单工厂模式,虽然直接修改工厂类会导致违反开闭原则,但在简单场景下,或者产品种类较少、不易变动时,仍不失为一种实用的选择。如果预计产品种类会频繁增加或变动,建议使用工厂方法或抽象工厂模式。
    3. 处理依赖关系

      • 如果产品类之间存在复杂的依赖关系,或者需要一起创建一组相关对象,应考虑使用抽象工厂模式,它能更好地管理产品族的创建。
      • 对于简单工厂或工厂方法模式,如果产品类的依赖关系比较简单,可以直接在工厂中创建或注入依赖。如果依赖关系较复杂,可能需要配合依赖注入框架或服务定位器模式来管理。
    4. 控制类的个数

      • 工厂模式可能会增加类的数量,特别是在产品种类较多时。应合理规划类结构,避免类爆炸。可以通过模块化、分包等方式组织代码,提高可读性和可维护性。
      • 对于简单工厂模式,如果产品种类过多导致工厂类庞大,可以考虑使用策略模式或枚举类等方式替代部分简单工厂功能。
    5. 考虑使用场景

      • 工厂模式并非所有情况下的首选解决方案。对于简单对象的创建,直接使用构造函数或静态工厂方法可能更为简洁。只有在对象创建逻辑复杂、需要动态决定创建何种对象,或者希望将对象创建细节与使用分离时,才应考虑使用工厂模式。
    6. 测试与调试

      • 工厂模式可能会增加代码的复杂性,影响测试的便利性。应确保工厂类及其创建的产品类具有良好的可测试性,如提供适当的构造函数、依赖注入点或模拟接口,以便于单元测试。
      • 调试时,注意跟踪工厂创建对象的过程,特别是涉及多层工厂或工厂链时,确保对象的创建路径符合预期。
    7. 代码复用与扩展

      • 如果多个工厂有相似的创建逻辑,可以考虑提取公共部分到基类或工具类中,避免代码重复。
      • 在设计工厂接口时,要考虑未来的扩展性,确保接口定义能够适应潜在的新产品类型。
    8. 性能与资源管理

      • 如果工厂模式用于创建资源密集型对象(如数据库连接、文件句柄等),需要考虑资源的有效管理和回收,避免资源泄露。
      • 对于工厂方法模式,如果工厂类实例化成本较高,可以考虑使用单例模式或享元模式来优化。

    总结来说,使用工厂模式时,应关注职责划分、开闭原则的遵循、依赖关系管理、类数量控制、使用场景选择、测试与调试的便利性、代码复用与扩展性以及性能与资源管理等方面的问题,以确保模式的有效运用和系统的健壮性。

  • 相关阅读:
    mq 消息队列
    LeetCode941. Valid Mountain Array
    CAS策略
    如何在 Docker 容器中运行 MySQL
    EDI对接 New York & Company案例
    Electron:窗口、窗口标题和边框
    SpringBoot项目的搭建
    【Android】-- Activity页面(启动和结束、生命周期、启动模式和实例)
    计算机网络:数据链路层设备 网桥与交换机
    猿创征文|Spring5梦开始的地方:入门必看
  • 原文地址:https://blog.csdn.net/Rcain_R/article/details/137977441