首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

设计模式 —— 工厂模式(简单工厂、工厂方法、抽象工厂)

  • 25-03-07 20:22
  • 2783
  • 8380
blog.csdn.net

目录

一、简单工厂模式

1.1 使用传统的方式来完成

1.2 传统的方式的优缺点

二、简单工厂

2.1 简单工厂基本介绍

2.2 使用简单工厂模式

三、工厂方法模式

3.1 工厂方法模式介绍

3.2 工厂方法模式应用案例

四、抽象工厂模式

4.1 抽象工厂基本介绍

4.2 抽象工厂模式应用实例

五、工厂模式在 JDK-Calendar 应用的源码分析

六、工厂模式小结


一、简单工厂模式

看一个披萨的项目:要便于披萨种类的扩展,要便于维护

  1. 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
  2. 披萨的制作有 prepare,bake, cut, box
  3. 完成披萨店订购功能。

1.1 使用传统的方式来完成

思路分析(类图)

编写 OrderPizza.java 去订购需要的各种 Pizza,传统方式代码如下:

  1. public class OrderPizza {
  2. // 构造器
  3. public OrderPizza() {
  4. Pizza pizza = null;
  5. String orderType; // 订购披萨的类型
  6. do {
  7. orderType = getType();
  8. if (orderType.equals("greek")) {
  9. pizza = new GreekPizza();
  10. pizza.setName(" 希腊披萨 ");
  11. } else if (orderType.equals("cheese")) {
  12. pizza = new CheesePizza();
  13. pizza.setName(" 奶酪披萨 ");
  14. } else if (orderType.equals("pepper")) {
  15. pizza = new PepperPizza();
  16. pizza.setName("胡椒披萨");
  17. } else {
  18. break;
  19. }
  20. //输出 pizza 制作过程
  21. pizza.prepare();
  22. pizza.bake();
  23. pizza.cut();
  24. pizza.box();
  25. } while (true);
  26. }
  27. public String getType() {
  28. return "";
  29. }
  30. }
  31. abstract class Pizza{
  32. public void setName(String name){}
  33. public void prepare(){}
  34. public void bake() {}
  35. public void cut() {}
  36. public void box() {}
  37. }
  38. class GreekPizza extends Pizza{
  39. }
  40. class CheesePizza extends Pizza {
  41. }
  42. class PepperPizza extends Pizza {
  43. }

1.2 传统的方式的优缺点

  1. 优点是比较好理解,简单易操作。
  2. 缺点是违反了设计模式的 ocp 原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码.
  3. 比如我们这时要新增加一个 Pizza 的种类(Pepper 披萨),我们需要做如下修改. 如果我们增加一个 Pizza 类,只要是订购 Pizza 的代码都需要修改.

改进的思路分析

  • 分析:修改代码可以接受,但是如果我们在其它的地方也有创建 Pizza 的代码,就意味着,也需要修改,而创建 Pizza 的代码,往往有多处。
  • 思路:把创建 Pizza 对象封装到一个类中,这样我们有新的 Pizza 种类时,只需要修改该类就可,其它有创建到 Pizza 对象的代码就不需要修改了  ->  简单工厂模式

二、简单工厂

2.1 简单工厂基本介绍

  1. 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
  2. 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
  3. 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式

2.2 使用简单工厂模式

简单工厂模式的设计方案: 定义一个可以实例化 Pizaa 对象的类,封装创建对象的代码。

示例代码:

  1. // 简单工厂类
  2. public class SimpleFactory {
  3. // 简单工厂模式 也叫 静态工厂模式
  4. public static Pizza createPizza(String orderType) {
  5. Pizza pizza = null;
  6. System.out.println("使用简单工厂模式");
  7. if (orderType.equals("greek")) {
  8. pizza = new GreekPizza();
  9. pizza.setName(" 希腊披萨 ");
  10. } else if (orderType.equals("cheese")) {
  11. pizza = new CheesePizza();
  12. pizza.setName(" 奶酪披萨 ");
  13. } else if (orderType.equals("pepper")) {
  14. pizza = new PepperPizza();
  15. pizza.setName("胡椒披萨");
  16. }
  17. return pizza;
  18. }
  19. }
  1. public class OrderPizza {
  2. //定义一个简单工厂对象
  3. SimpleFactory simpleFactory;
  4. Pizza pizza = null;
  5. //构造器
  6. public OrderPizza(SimpleFactory simpleFactory) {
  7. setFactory(simpleFactory);
  8. }
  9. public void setFactory(SimpleFactory simpleFactory) {
  10. String orderType = ""; //用户输入的
  11. this.simpleFactory = simpleFactory; //设置简单工厂对象
  12. do {
  13. orderType = getType();
  14. pizza = this.simpleFactory.createPizza(orderType);
  15. //输出 pizza
  16. if (pizza != null) { //订购成功
  17. pizza.prepare();
  18. pizza.bake();
  19. pizza.cut();
  20. pizza.box();
  21. } else {
  22. System.out.println(" 订购披萨失败 ");
  23. break;
  24. }
  25. } while (true);
  26. }
  27. // 写一个方法,可以获取客户希望订购的披萨种类
  28. private String getType() {
  29. try {
  30. BufferedReader strIn = new BufferedReader(new InputStreamReader(System.in));
  31. System.out.println("input pizza 种类:");
  32. String str = strIn.readLine();
  33. return str;
  34. } catch (IOException e) {
  35. e.printStackTrace(); return "";
  36. }
  37. }
  38. }

三、工厂方法模式

  • 看一个新的需求

披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza。

 

  • 思路 1

使用简单工厂模式,创建不同的简单工厂类,比如 BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等.从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好

 

  • 思路 2

使用工厂方法模式


3.1 工厂方法模式介绍

  1. 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
  2. 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。

3.2 工厂方法模式应用案例

披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza

思路分析图解

代码实现

  1. public class BJCheesePizza extends Pizza {
  2. }
  1. public class BJPepperPizza extends Pizza {
  2. }
  1. public class LDCheesePizza extends Pizza {
  2. }
  1. public class LDPepperPizza extends Pizza {
  2. }
  1. public abstract class AbstractOrderPizza {
  2. //定义一个抽象方法,createPizza , 让各个工厂子类自己实现
  3. abstract Pizza createPizza(String orderType);
  4. // 构造器
  5. public AbstractOrderPizza() { Pizza pizza = null;
  6. String orderType; // 订购披萨的类型
  7. do {
  8. orderType = getType();
  9. pizza = createPizza(orderType); //抽象方法,由工厂子类完成
  10. //输出 pizza 制作过程
  11. pizza.prepare();
  12. pizza.bake();
  13. pizza.cut();
  14. pizza.box();
  15. } while (true);
  16. }
  17. // 写一个方法,可以获取客户希望订购的披萨种类
  18. private String getType() {
  19. try {
  20. BufferedReader strIn = new BufferedReader(new InputStreamReader(System.in));
  21. System.out.println("input pizza 种类:");
  22. String str = strIn.readLine();
  23. return str;
  24. } catch (IOException e) {
  25. e.printStackTrace(); return "";
  26. }
  27. }
  28. }
  1. public class BJOrderPizza extends AbstractOrderPizza {
  2. @Override
  3. Pizza createPizza(String orderType) {
  4. Pizza pizza = null;
  5. if(orderType.equals("cheese")) {
  6. pizza = new BJCheesePizza();
  7. } else if (orderType.equals("pepper")) {
  8. pizza = new BJPepperPizza();
  9. }
  10. return pizza;
  11. }
  12. }
  1. public class LDOrderPizza extends AbstractOrderPizza {
  2. @Override
  3. Pizza createPizza(String orderType) {
  4. Pizza pizza = null; if(orderType.equals("cheese")) {
  5. pizza = new LDCheesePizza();
  6. } else if (orderType.equals("pepper")) {
  7. pizza = new LDPepperPizza();
  8. }
  9. return pizza;
  10. }
  11. }

四、抽象工厂模式

4.1 抽象工厂基本介绍

  1. 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  2. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
  3. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
  4. 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

类图

4.2 抽象工厂模式应用实例

使用抽象工厂模式来完成披萨项目.

  1. //一个抽象工厂模式的抽象层(接口)
  2. public interface AbsFactory {
  3. //让下面的工厂子类来 具体实现
  4. public Pizza createPizza(String orderType);
  5. }
  1. //这是工厂子类
  2. public class BJFactory implements AbsFactory {
  3. @Override
  4. public Pizza createPizza(String orderType) {
  5. System.out.println("~使用的是抽象工厂模式~");
  6. Pizza pizza = null;
  7. if(orderType.equals("cheese")) {
  8. pizza = new BJCheesePizza();
  9. } else if (orderType.equals("pepper")){
  10. pizza = new BJPepperPizza();
  11. }
  12. return pizza;
  13. }
  14. }
  1. public class LDFactory implements AbsFactory {
  2. @Override
  3. public Pizza createPizza(String orderType) {
  4. System.out.println("~使用的是抽象工厂模式~");
  5. Pizza pizza = null;
  6. if (orderType.equals("cheese")) {
  7. pizza = new LDCheesePizza();
  8. } else if (orderType.equals("pepper")) {
  9. pizza = new LDPepperPizza();
  10. }
  11. return pizza;
  12. }
  13. }
  1. public class OrderPizza {
  2. AbsFactory factory;
  3. // 构造器
  4. public OrderPizza(AbsFactory factory) {
  5. setFactory(factory);
  6. }
  7. private void setFactory(AbsFactory factory) {
  8. Pizza pizza = null;
  9. String orderType = ""; // 用户输入
  10. this.factory = factory; do {
  11. orderType = getType();
  12. // factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
  13. pizza = factory.createPizza(orderType);
  14. if (pizza != null) { // 订 购 ok
  15. pizza.prepare();
  16. pizza.bake();
  17. pizza.cut();
  18. pizza.box();
  19. } else {
  20. System.out.println("订购失败");
  21. break;
  22. }
  23. } while (true);
  24. }
  25. // 写一个方法,可以获取客户希望订购的披萨种类
  26. private String getType() {
  27. try {
  28. BufferedReader strIn = new BufferedReader(new InputStreamReader(System.in));
  29. System.out.println("input pizza 种类:");
  30. String str = strIn.readLine();
  31. return str;
  32. } catch (IOException e) {
  33. e.printStackTrace(); return "";
  34. }
  35. }
  36. }

五、工厂模式在 JDK-Calendar 应用的源码分析

  • JDK 中的 Calendar 类中,就使用了简单工厂模式
  • 源码分析+Debug 源码+说明
  1. import java.util.Calendar;
  2. public class Factory {
  3. public static void main(String[] args) {
  4. // getInstance 是 Calendar 静态方法
  5. Calendar cal = Calendar.getInstance();
  6. // 注意月份下标从 0 开始,所以取月份要+1
  7. System.out.println("年:" + cal.get(Calendar.YEAR));
  8. System.out.println(" 月 :" + (cal.get(Calendar.MONTH) + 1));
  9. System.out.println("日:" + cal.get(Calendar.DAY_OF_MONTH));
  10. System.out.println("时:" + cal.get(Calendar.HOUR_OF_DAY));
  11. System.out.println("分:" + cal.get(Calendar.MINUTE));
  12. System.out.println("秒:" + cal.get(Calendar.SECOND));
  13. }
  14. }

在Calendar.java 中:

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

六、工厂模式小结

  1. 工厂模式的意义: 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
  2. 三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
  3. 设计模式的依赖抽象原则

使用建议:

  • 创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说, 变量不要直接持有具体类的引用。
  • 不要让类继承具体类,而是继承抽象类或者是实现 interface(接口)
  • 不要覆盖基类中已经实现的方法。

 


文章最后,给大家推荐一些受欢迎的技术博客链接:

  1. JAVA相关的深度技术博客链接
  2. Flink 相关技术博客链接
  3. Spark 核心技术链接
  4. 设计模式 —— 深度技术博客链接
  5. 机器学习 —— 深度技术博客链接
  6. Hadoop相关技术博客链接
  7. 超全干货--Flink思维导图,花了3周左右编写、校对
  8. 深入JAVA 的JVM核心原理解决线上各种故障【附案例】
  9. 请谈谈你对volatile的理解?--最近小李子与面试官的一场“硬核较量”
  10. 聊聊RPC通信,经常被问到的一道面试题。源码+笔记,包懂
  11. 深入聊聊Java 垃圾回收机制【附原理图及调优方法】

欢迎扫描下方的二维码或 搜索 公众号“大数据高级架构师”,我们会有更多、且及时的资料推送给您,欢迎多多交流!

                                           

       

 

注:本文转载自blog.csdn.net的不埋雷的探长的文章"https://blog.csdn.net/weixin_32265569/article/details/108314331"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top