经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
创建模式--工厂模式、抽象工厂模式
来源:cnblogs  作者:累成一条狗  时间:2019/8/7 8:50:26  对本文有异议

一、小案例分析

1、功能需求:

  实现一个发送信息的功能,要便于扩展与维护。
(1)发送信息的工具有很多,比如短信、微信、邮件、QQ等。
(2)选择某个工具进行信息发送。

2、小菜鸡去实现:

(1)定义一个发送工具的父类(接口),并将各种发送工具作为子类(实现类)。
(2)定义一个选择发送工具的类,用于调用发送工具(直接new个子类对象)。
(3)代码实现:

  1. package creative.pattern.factory.noFactory;
  2. import java.util.Scanner;
  3. /**
  4. * 测试类
  5. *
  6. */
  7. public class Demo {
  8. public static void main(String[] args) {
  9. new SendMessage();// 实例化一个选择发送工具的类
  10. }
  11. }
  12. /**
  13. * 定义一个发送工具的接口
  14. *
  15. */
  16. interface Sender {
  17. void sendMessage();
  18. }
  19. /**
  20. * 定义一个短信发送工具,实现接口,重写方法
  21. *
  22. */
  23. class ShortMessageSender implements Sender {
  24. @Override
  25. public void sendMessage() {
  26. System.out.println("发送短信");
  27. }
  28. }
  29. /**
  30. * 定义一个微信发送工具,实现接口,重写方法
  31. *
  32. */
  33. class WeChatSender implements Sender {
  34. @Override
  35. public void sendMessage() {
  36. System.out.println("发送微信");
  37. }
  38. }
  39. /**
  40. * 定义一个邮件发送工具,实现接口,重写方法
  41. *
  42. */
  43. class MailSender implements Sender {
  44. @Override
  45. public void sendMessage() {
  46. System.out.println("发送邮件");
  47. }
  48. }
  49. /**
  50. * 定义一个选择发送工具的类
  51. */
  52. class SendMessage {
  53. /**
  54. * 用于获取需要发送信息工具
  55. */
  56. public Sender getSenderType() {
  57. System.out.println("输入发送工具的类型(1-3):");
  58. System.out.println("1:短信");
  59. System.out.println("2:微信");
  60. System.out.println("3:邮件");
  61. Scanner scanner = new Scanner(System.in);
  62. String senderType = scanner.nextLine();
  63. if ("1".equals(senderType)) {
  64. return new ShortMessageSender();
  65. } else if ("2".equals(senderType)) {
  66. return new WeChatSender();
  67. } else if ("3".equals(senderType)) {
  68. return new MailSender();
  69. } else {
  70. return null;
  71. }
  72. }
  73. public SendMessage() {
  74. do {
  75. Sender sender = getSenderType();// 选择发送信息的工具
  76. if (sender == null) {
  77. System.out.println("欢迎下次使用");
  78. break;
  79. } else {
  80. sender.sendMessage();
  81. }
  82. } while (true);
  83. }
  84. }

(4)代码分析:
  对于逻辑简单的代码,这样实现没有问题,但是逻辑稍微复杂一些且需要修改扩展某个地方时,需要改动很多地方。
  比如:再增加一个 QQSender,其需要实现Sender接口,并重写相关方法,然后需要在 SendMessage 类中 去修改相关代码,这里违反了开闭原则。若需要增加几个SendMessage 类,比如SendMessage2、SendMessage3时,同样需要改动很多代码。
(5)UML图:

 

二、简单工厂模式(SimpleFactory)

1、什么是简单工厂模式:

  简单工厂模式属于创建型模式,不属于常见的23种常见模式。简单的讲 简单工厂模式是由一个工厂对象决定创建出哪一类产品的实例。

2、使用:

(1)简单工厂模式,定义了一个创建对象的类,然后由这个类来封装实例化对象的操作。
(2)当需要大量创建某种类或者对象时,可以使用工厂模式。

3、使用简单工厂模式实现:

(1)定义一个发送工具的父类(接口),并将各种发送工具作为子类(实现类)。
(2)定义一个工厂类,用于调用发送工具。
(2)定义一个选择发送工具的类,用于调用工厂类。
(3)代码实现:

  1. package creative.pattern.factory.simpleFactory;
  2. import java.util.Scanner;
  3. /**
  4. * 测试类
  5. *
  6. */
  7. public class SimpleFactoryDemo {
  8. public static void main(String[] args) {
  9. new SendMessage();
  10. }
  11. }
  12. /**
  13. * 定义一个发送工具的接口
  14. *
  15. */
  16. interface Sender {
  17. void sendMessage();
  18. }
  19. /**
  20. * 定义一个短信发送工具,实现接口,重写方法
  21. *
  22. */
  23. class ShortMessageSender implements Sender {
  24. @Override
  25. public void sendMessage() {
  26. System.out.println("发送短信");
  27. }
  28. }
  29. /**
  30. * 定义一个微信发送工具,实现接口,重写方法
  31. *
  32. */
  33. class WeChatSender implements Sender {
  34. @Override
  35. public void sendMessage() {
  36. System.out.println("发送微信");
  37. }
  38. }
  39. /**
  40. * 定义一个邮件发送工具,实现接口,重写方法
  41. *
  42. */
  43. class MailSender implements Sender {
  44. @Override
  45. public void sendMessage() {
  46. System.out.println("发送邮件");
  47. }
  48. }
  49. /**
  50. * 使用简单工厂模式,管理需要生产的对象
  51. *
  52. */
  53. class SimpleFactory {
  54. /**
  55. * 用于获取需要发送信息工具
  56. */
  57. public static Sender createSender() {
  58. System.out.println("输入发送工具的类型(1-3):");
  59. System.out.println("1:短信");
  60. System.out.println("2:微信");
  61. System.out.println("3:邮件");
  62. Scanner scanner = new Scanner(System.in);
  63. String senderType = scanner.nextLine();
  64. if ("1".equals(senderType)) {
  65. return new ShortMessageSender();
  66. } else if ("2".equals(senderType)) {
  67. return new WeChatSender();
  68. } else if ("3".equals(senderType)) {
  69. return new MailSender();
  70. } else {
  71. return null;
  72. }
  73. }
  74. }
  75. /**
  76. * 定义一个选择发送工具的类
  77. */
  78. class SendMessage {
  79. public SendMessage() {
  80. do {
  81. Sender sender = SimpleFactory.createSender();// 选择发送信息的工具
  82. if (sender == null) {
  83. System.out.println("欢迎下次使用");
  84. break;
  85. } else {
  86. sender.sendMessage();
  87. }
  88. } while (true);
  89. }
  90. }

(4)代码分析:
  对于上述代码,SendMessage 只与工厂类SimpleFactory 相关联,此时需要扩展代码时,比如扩展QQSender,让其实现Sender并重写方法后,在SimpleFactory 中改变相关代码即可(违反开闭原则),不需要再改动SendMessage 的代码。
(5)UML图:

 

4、使用静态工厂模式实现(常用形式):

  将上例的SimpleFactory 中public Sender createSender()改为 public static Sender createSender()。
  调用时,直接使用SimpleFactory.createSender() 即可。

  1. public static Sender createSender() {
  2. System.out.println("输入发送工具的类型(1-3):");
  3. System.out.println("1:短信");
  4. System.out.println("2:微信");
  5. System.out.println("3:邮件");
  6. Scanner scanner = new Scanner(System.in);
  7. String senderType = scanner.nextLine();
  8. if ("1".equals(senderType)) {
  9. return new ShortMessageSender();
  10. } else if ("2".equals(senderType)) {
  11. return new WeChatSender();
  12. } else if ("3".equals(senderType)) {
  13. return new MailSender();
  14. } else {
  15. return null;
  16. }
  17. }

三、工厂方法模式

1、什么是工厂方法模式:

  在工厂内部定义一个创建对象的抽象方法,由子类去确定要实例化的对象。简单的讲 工厂方法模式将对象实例化的操作推迟到子类去实现。可以看做抽象工厂模式的一个常见类型。

2、使用工厂模式实现:

(1)定义一个发送工具的父类(接口),并将各种发送工具作为子类(实现类)。
(2)定义一个工厂方法接口,并通过工厂实现类去实例化对象。
(3)定义一个选择发送工具的类,用于调用工厂实现类。
(4)代码实现:

  1. package creative.pattern.factory.factoryMethod;
  2. import java.util.Scanner;
  3. /**
  4. * 工厂方法模式测试类
  5. *
  6. */
  7. public class factoryMethodDemo {
  8. public static void main(String[] args) {
  9. new SendMessage();
  10. }
  11. }
  12. /**
  13. * 定义一个发送工具的接口
  14. *
  15. */
  16. interface Sender {
  17. void sendMessage();
  18. }
  19. /**
  20. * 定义一个短信发送工具,实现接口,重写方法
  21. *
  22. */
  23. class ShortMessageSender implements Sender {
  24. @Override
  25. public void sendMessage() {
  26. System.out.println("发送短信");
  27. }
  28. }
  29. /**
  30. * 定义一个微信发送工具,实现接口,重写方法
  31. *
  32. */
  33. class WeChatSender implements Sender {
  34. @Override
  35. public void sendMessage() {
  36. System.out.println("发送微信");
  37. }
  38. }
  39. /**
  40. * 定义一个邮件发送工具,实现接口,重写方法
  41. *
  42. */
  43. class MailSender implements Sender {
  44. @Override
  45. public void sendMessage() {
  46. System.out.println("发送邮件");
  47. }
  48. }
  49. /**
  50. * 使用工厂方法模式,让子类去创建对象
  51. *
  52. */
  53. interface FactoryMethod {
  54. Sender sendMessage();
  55. }
  56. /**
  57. * 短信工厂类,实现工厂方法类并重写相关方法
  58. *
  59. */
  60. class ShortMessageFactory implements FactoryMethod {
  61. @Override
  62. public Sender sendMessage() {
  63. return new ShortMessageSender();
  64. }
  65. }
  66. /**
  67. * 微信工厂类,实现工厂方法类并重写相关方法
  68. *
  69. */
  70. class WeChatFactory implements FactoryMethod {
  71. @Override
  72. public Sender sendMessage() {
  73. return new WeChatSender();
  74. }
  75. }
  76. /**
  77. * 邮件工厂类,实现工厂方法类并重写相关方法
  78. *
  79. */
  80. class MailFactory implements FactoryMethod {
  81. @Override
  82. public Sender sendMessage() {
  83. return new MailSender();
  84. }
  85. }
  86. /**
  87. * 定义一个选择发送工具的类
  88. */
  89. class SendMessage {
  90. public SendMessage() {
  91. do {
  92. System.out.println("输入发送工具的类型(1-3):");
  93. System.out.println("1:短信");
  94. System.out.println("2:微信");
  95. System.out.println("3:邮件");
  96. Scanner scanner = new Scanner(System.in);
  97. String senderType = scanner.nextLine();
  98. if ("1".equals(senderType)) {
  99. FactoryMethod factoryMethod = new ShortMessageFactory();
  100. Sender sender = factoryMethod.sendMessage();// 选择发送短信
  101. sender.sendMessage();
  102. } else if ("2".equals(senderType)) {
  103. FactoryMethod factoryMethod = new WeChatFactory();
  104. Sender sender = factoryMethod.sendMessage();// 选择发送微信
  105. sender.sendMessage();
  106. } else if ("3".equals(senderType)) {
  107. FactoryMethod factoryMethod = new MailFactory();
  108. Sender sender = factoryMethod.sendMessage();// 选择发送邮件
  109. sender.sendMessage();
  110. } else {
  111. System.out.println("欢迎下次使用");
  112. break;
  113. }
  114. } while (true);
  115. }
  116. }

(5)代码分析:
  SendMessage 类只与FactoryMethod 有关,当扩展新的功能时,比如QQSender,只需创建一个QQFactory,实现FactoryMethod 并重写其方法即可,调用时无需更改其他代码(必要的逻辑处理除外,符合开闭原则)。
(6)UML图:

 

四、抽象工厂模式

1、什么是抽象工厂模式

  为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
注:
  产品族:是指位于不同产品等级结构中功能相关联的产品组成的家族。
  产品等级结构:可以理解为一个接口或者一个抽象类。

2、抽象工厂模式与工厂方法模式的区别

(1)抽象工厂模式是工厂方法模式的升级版,其针对的是多个产品等级结构,即抽象工厂模式所提供的产品是衍生自不同的接口或抽象类。
(2)工厂方法模式:针对一个产品等级结构,即工厂方法模式衍生自同一个接口或者抽象类。
(3)如下图所示,ShortMessage 与 WeChat属于同一个产品等级,ShortMessage 与 ShortMessage2属于两个产品等级,为产品族。所以若存在两个产品等级及以上的情况,即为抽象工厂模式,若是同一个产品等级,则为工厂方法模式。
  下图为工厂方法模式:

下图为抽象工厂模式:

3、举例:

  在之前案例的基础上,增加一个功能,微信、短信均可以图片。
(1)定义一个发送工具的父类(接口),并将各种发送工具作为子类(实现类)。
(2)定义一个工厂方法接口,在方法中对产品族进行约束,并通过工厂实现类去实例化对象。
(3)定义一个选择发送工具的类(测试类),用于调用工厂实现类。
(4)代码实现:

  1. package creative.pattern.factory.absFactory;
  2. /**
  3. * 抽象工厂模式测试类
  4. *
  5. */
  6. public class AbsFactoryDemo {
  7. public static void main(String[] args) {
  8. AbsFactory absFactory = new WeChatFactory();
  9. absFactory.getSender().sendMessage();
  10. absFactory.getSender2().sendMessage();
  11. ((WeChatSender2) absFactory.getSender2()).sendPicture();
  12. AbsFactory absFactory2 = new ShortMessageFactory();
  13. absFactory2.getSender().sendMessage();
  14. absFactory2.getSender2().sendMessage();
  15. ((ShortMessageSender2) absFactory2.getSender2()).sendPicture();
  16. }
  17. }
  18. /**
  19. * 定义一个发送工具的接口
  20. *
  21. */
  22. interface Sender {
  23. void sendMessage();
  24. }
  25. /**
  26. * 定义一个微信发送工具,实现接口,重写方法
  27. *
  28. */
  29. class WeChatSender implements Sender {
  30. @Override
  31. public void sendMessage() {
  32. System.out.println("使用微信,发送短信");
  33. }
  34. }
  35. /**
  36. * 定义一个微信发送工具,实现接口,重写方法,并新增自己的方法
  37. *
  38. */
  39. class WeChatSender2 implements Sender {
  40. @Override
  41. public void sendMessage() {
  42. System.out.println("使用微信,发送短信");
  43. }
  44. public void sendPicture() {
  45. System.out.println("使用微信,发送图片");
  46. }
  47. }
  48. /**
  49. * 定义一个短信发送工具,实现接口,重写方法
  50. *
  51. */
  52. class ShortMessageSender implements Sender {
  53. @Override
  54. public void sendMessage() {
  55. System.out.println("使用短信,发送短信");
  56. }
  57. }
  58. /**
  59. * 定义一个短信发送工具,实现接口,重写方法,并新增自己的方法
  60. *
  61. */
  62. class ShortMessageSender2 implements Sender {
  63. @Override
  64. public void sendMessage() {
  65. System.out.println("使用短信,发送短信");
  66. }
  67. public void sendPicture() {
  68. System.out.println("使用短信,发送图片");
  69. }
  70. }
  71. /**
  72. * 抽象工厂模式
  73. *
  74. */
  75. interface AbsFactory {
  76. Sender getSender();
  77. Sender getSender2();
  78. }
  79. /**
  80. * 工厂子类,实现抽象工厂类,重写相关方法,
  81. *
  82. */
  83. class WeChatFactory implements AbsFactory {
  84. @Override
  85. public Sender getSender() {
  86. return new WeChatSender();
  87. }
  88. @Override
  89. public Sender getSender2() {
  90. return new WeChatSender2();
  91. }
  92. }
  93. /**
  94. * 工厂子类,实现抽象工厂类,重写相关方法,
  95. *
  96. */
  97. class ShortMessageFactory implements AbsFactory {
  98. @Override
  99. public Sender getSender() {
  100. return new ShortMessageSender();
  101. }
  102. @Override
  103. public Sender getSender2() {
  104. return new ShortMessageSender2();
  105. }
  106. }

(5)代码分析:
  对于产品族,定义在一个接口中,然后通过不同的子类去实现。扩展时,只需要实现接口并重写相关方法即可,满足开闭原则。

(6)UML图:

五、JDK中工厂模式举例(Calendar)

1、部分源码

  1. public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
  2. /**
  3. * Gets a calendar using the default time zone and locale. The
  4. * <code>Calendar</code> returned is based on the current time
  5. * in the default time zone with the default
  6. * {@link Locale.Category#FORMAT FORMAT} locale.
  7. *
  8. * @return a Calendar.
  9. */
  10. public static Calendar getInstance()
  11. {
  12. return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
  13. }
  14. private static Calendar createCalendar(TimeZone zone,
  15. Locale aLocale)
  16. {
  17. CalendarProvider provider =
  18. LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
  19. .getCalendarProvider();
  20. if (provider != null) {
  21. try {
  22. return provider.getInstance(zone, aLocale);
  23. } catch (IllegalArgumentException iae) {
  24. // fall back to the default instantiation
  25. }
  26. }
  27. Calendar cal = null;
  28. if (aLocale.hasExtensions()) {
  29. String caltype = aLocale.getUnicodeLocaleType("ca");
  30. if (caltype != null) {
  31. switch (caltype) {
  32. case "buddhist":
  33. cal = new BuddhistCalendar(zone, aLocale);
  34. break;
  35. case "japanese":
  36. cal = new JapaneseImperialCalendar(zone, aLocale);
  37. break;
  38. case "gregory":
  39. cal = new GregorianCalendar(zone, aLocale);
  40. break;
  41. }
  42. }
  43. }
  44. if (cal == null) {
  45. // If no known calendar type is explicitly specified,
  46. // perform the traditional way to create a Calendar:
  47. // create a BuddhistCalendar for th_TH locale,
  48. // a JapaneseImperialCalendar for ja_JP_JP locale, or
  49. // a GregorianCalendar for any other locales.
  50. // NOTE: The language, country and variant strings are interned.
  51. if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
  52. cal = new BuddhistCalendar(zone, aLocale);
  53. } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
  54. && aLocale.getCountry() == "JP") {
  55. cal = new JapaneseImperialCalendar(zone, aLocale);
  56. } else {
  57. cal = new GregorianCalendar(zone, aLocale);
  58. }
  59. }
  60. return cal;
  61. }
  62. }

2、源码分析

  Calendar内部采用简单工厂模式进行对象的实例化。其根据不同的逻辑判断条件来选择实例化具体的对象。

 

六、总结:

1、工厂模式的意义:

  将实例化对象的代码提取出来,放到一个类(工厂类)里面进行维护,使其与主项目解耦,提高程序的维护性与扩展性。

2、传统模式:

  直接在需要的地方实例化某对象。扩展代码时,需要在使用到的地方进行修改,违反了开闭原则。

3、简单工厂模式:

  在需要用到的地方,调用工厂类即可,扩展代码时,修改工厂类即可,也违反了开闭原则。
(1)简单工厂模式(普通方法):
  使用一个工厂类,在某方法中通过逻辑处理并实例化需要的对象。
(2)简单工厂模式(静态方法):
  将简单工厂模式(普通方法)的普通方法改为静态方法,并通过”类名.方法名“来调用。
(3)简单工厂模式(多方法):
  使用一个工厂类,并通过调用不同的方法去实例化不同的对象。

4、工厂方法模式:

  使用一个工厂类接口与多个工厂实现类,在不同的工厂实现类中去实例化不同的对象。扩展代码时,定义一个工厂实现类,实现工厂类接口并重写相关方法即可,满足开闭原则。可以理解为抽象工厂模式的一般形式。

5、抽象工厂模式:

  可以理解为工厂方法模式的升级版,其在一个接口中定义了一个产品族的处理(多个方法),子类实现该接口,并重写相关方法即可,扩展类似于工厂方法模式,满足开闭原则。

原文链接:http://www.cnblogs.com/l-y-h/p/11305441.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号