—-慢慢来比较快,虚心学技术—-
**

工厂模式必备基础概念

产品

类,如阿迪家的鞋(具体的产品)

抽象产品

抽象类,抽象类的实现类,如阿迪的鞋品牌

产品等级

产品类别,如鞋

产品簇

同一品牌的产品族,如阿迪的所有产品(鞋,运动上衣,运动裤等)

图片.png

概念

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

模式结构:抽象工厂:抽象工厂产品:抽象产品:具体产品

抽象工厂:提供了创建产品的接口,它包含了多个创建产品的方法,可以创建多个不同等级的产品

抽象工厂产品:实现了抽象工厂的多个抽象方法,完成了具体产品的创建

抽象产品:定义了产品的规范,描述了产品的主要特征和功能

具体产品:实现了抽象产品的多个接口,由抽象工厂产品创建

推演

工厂方法例子

生产8毫米及6毫米螺丝的需求

  1. /**
  2. * 螺丝工厂接口
  3. */
  4. interface ScrewFactory{
  5. Screw getScrew();
  6. }
  7. /**
  8. * 工厂接口具体产品 - 8毫米螺丝工厂
  9. */
  10. class EightScrewFactory implements ScrewFactory {
  11. @Override
  12. public Screw getScrew() {
  13. return new EightScrew();
  14. }
  15. }
  16. /**
  17. * 工厂接口具体产品 - 6毫米螺丝工厂
  18. */
  19. class SixScrewFactory implements ScrewFactory {
  20. @Override
  21. public Screw getScrew() {
  22. return new SixScrew();
  23. }
  24. }
  25. /**
  26. * 接口类,抽象产品-螺丝
  27. */
  28. interface Screw{
  29. Integer getDiameter();
  30. }
  31. /**
  32. * 实现类,具体产品-8毫米螺丝
  33. */
  34. class EightScrew implements Screw {
  35. @Override
  36. public Integer getDiameter() {
  37. return 8;
  38. }
  39. }
  40. /**
  41. * 实现类,具体产品-6毫米螺丝
  42. */
  43. class SixScrew implements Screw {
  44. @Override
  45. public Integer getDiameter() {
  46. return 6;
  47. }
  48. }

生产8毫米和6毫米螺丝帽的需求

  1. /**
  2. * 螺丝帽工厂接口
  3. */
  4. interface ScrewCapFactory{
  5. ScrewCap getScrewCap();
  6. }
  7. /**
  8. * 工厂接口具体产品 - 8毫米螺丝工厂
  9. */
  10. class EightScrewCapFactory implements ScrewCapFactory {
  11. @Override
  12. public ScrewCap getScrewCap() {
  13. return new EightScrewCap();
  14. }
  15. }
  16. /**
  17. * 工厂接口具体产品 - 6毫米螺丝工厂
  18. */
  19. class SixScrewCapFactory implements ScrewCapFactory {
  20. @Override
  21. public ScrewCap getScrewCap() {
  22. return new SixScrewCap();
  23. }
  24. }
  25. /**
  26. * 接口类,抽象产品-螺丝帽
  27. */
  28. interface ScrewCap{
  29. Integer getDiameter();
  30. }
  31. /**
  32. * 实现类,具体产品-8毫米螺丝帽
  33. */
  34. class EightScrewCap implements ScrewCap {
  35. @Override
  36. public Integer getDiameter() {
  37. return 8;
  38. }
  39. }
  40. /**
  41. * 实现类,具体产品-6毫米螺丝帽
  42. */
  43. class SixScrewCap implements ScrewCap {
  44. @Override
  45. public Integer getDiameter() {
  46. return 6;
  47. }
  48. }

客户端调用工厂生产配套的螺丝及螺丝帽

  1. ScrewFactory screwFactory = new EightScrewFactory();
  2. ScrewCapFactory screwCapFactory = new EightScrewCapFactory();
  3. Screw screw = screwFactory.getScrew();
  4. ScrewCap screwCap = screwCapFactory.getScrewCap();
  5. System.out.println("螺丝直径:"+screw.getDiameter()+"mm ----螺丝帽直径:"+screwCap.getDiameter()+"mm");

上述例子中,螺丝和螺丝帽是产品等级,Screw和ScrewCap都是抽象产品,而8毫米和6毫米螺丝(EightScrew和SixScrew)以及8毫米和6毫米螺丝帽(EightScrewCap 和SixScrewCap )都是产品

此时如果增加了一个产品等级如扳手,代码需要变动的地方分别是:

新增一个抽象产品——Spanner
新增两个具体产品——EightSpanner和SixSpanner
新增一个抽象工厂——SpannerFactory
新增两个工厂实现——EightSpannerFactory和SixSpannerFactory

此时客户端调用代码变动如下:

  1. ScrewFactory screwFactory = new EightScrewFactory();
  2. ScrewCapFactory screwCapFactory = new EightScrewCapFactory();
  3. Screw screw = screwFactory.getScrew();
  4. ScrewCap screwCap = screwCapFactory.getScrewCap();
  5. SpannerFactory spannerFactory= new EightSpannerFactory();
  6. Spanner spanner = spannerFactory.getSpanner();
  7. System.out.println("螺丝直径:"+screw.getDiameter()+"mm ----螺丝帽直径:"+screwCap.getDiameter()+"mm ----扳手直径:"+spanner.getDiameter()+"mm");

所以,工厂方法模式的弊端出现了,每添加了一个具体产品,都需要新增一个对应的具体工厂类,增加了代码的复杂度

抽象工厂例子

上述说明中,螺丝和螺丝帽是产品等级,Screw和ScrewCap都是抽象产品,而8毫米和6毫米螺丝(EightScrew和SixScrew)以及8毫米和6毫米螺丝帽(EightScrewCap 和SixScrewCap )都是产品

那么,很明显,螺丝和螺丝帽的组合,是一个产品簇(如8毫米螺丝和8毫米螺丝帽),抽象工厂则是将这种关联依赖形成统一的工厂进行生产

整合后代码如下:**

  1. /**
  2. * 抽象工厂,统一产品工厂
  3. */
  4. interface UnifiedFactory{
  5. Screw getScrew();
  6. ScrewCap getScrewCap();
  7. }
  8. /**
  9. * 工厂接口具体产品 - 8毫米产品统一工厂
  10. */
  11. class EightUnifiedFactory implements UnifiedFactory{
  12. @Override
  13. public Screw getScrew() {
  14. return new EightScrew();
  15. }
  16. @Override
  17. public ScrewCap getScrewCap() {
  18. return new EightScrewCap();
  19. }
  20. }
  21. /**
  22. * 工厂接口具体产品 - 6毫米产品统一工厂
  23. */
  24. class SixUnifiedFactory implements UnifiedFactory {
  25. @Override
  26. public Screw getScrew() {
  27. return new SixScrew();
  28. }
  29. @Override
  30. public ScrewCap getScrewCap() {
  31. return new SixScrewCap();
  32. }
  33. }
  34. /**
  35. * 接口类,抽象产品-螺丝
  36. */
  37. interface Screw{
  38. Integer getDiameter();
  39. }
  40. /**
  41. * 实现类,具体产品-8毫米螺丝
  42. */
  43. class EightScrew implements Screw {
  44. @Override
  45. public Integer getDiameter() {
  46. return 8;
  47. }
  48. }
  49. /**
  50. * 实现类,具体产品-6毫米螺丝
  51. */
  52. class SixScrew implements Screw {
  53. @Override
  54. public Integer getDiameter() {
  55. return 6;
  56. }
  57. }
  58. /**
  59. * 接口类,抽象产品-螺丝帽
  60. */
  61. interface ScrewCap{
  62. Integer getDiameter();
  63. }
  64. /**
  65. * 实现类,具体产品-8毫米螺丝帽
  66. */
  67. class EightScrewCap implements ScrewCap {
  68. @Override
  69. public Integer getDiameter() {
  70. return 8;
  71. }
  72. }
  73. /**
  74. * 实现类,具体产品-6毫米螺丝帽
  75. */
  76. class SixScrewCap implements ScrewCap {
  77. @Override
  78. public Integer getDiameter() {
  79. return 6;
  80. }
  81. }

客户端调用代码如下

  1. UnifiedFactory unifiedFactory = new EightUnifiedFactory();
  2. System.out.println("螺丝直径:"+unifiedFactory.getScrew().getDiameter()+"mm ----螺丝帽直径:"+unifiedFactory.getScrewCap().getDiameter()+"mm");

此时如果新增产品等级扳手(Spanner),则只需要如下操作:

新增一个抽象产品——Spanner
新增两个具体产品——EightSpanner和SixSpanner
在UnifiedFactory中新增方法Spanner getSpanner();
在EightUnifiedFactory和SixUnifiedFactory中实现getSpanner()方法分别生产EightSpanner和SixSpanner**

如此,便可解决工厂方法模式中的弊端,减少工厂的数量

应用场景

当产品等级比较固定时,可以考虑使用抽象工厂
当产品等级经常变化时,则不建议使用抽象工厂
**

优点

减少工厂类的数量,降低代码复杂度
**

缺点

如上述例子,当产品等级变化时,都要引起所有以前工厂代码的修改(如新增一个扳手产品等级,需要修改所有工厂代码),违反了“开闭原则”。

注:抽象工厂模式中,用一个工厂生产的产品都应该只属于同一个产品簇,必然存在内在联系

如有贻误,还请评论指正**