09.简单工厂模式与工厂方法模式

news2024/9/25 3:17:45

道生一,一生二,二生三,三生万物。——《道德经》

在这里插入图片描述
最近小米新车亮相的消息可以说引起了不小的轰动,我们在感慨SU7充满土豪气息的保时捷设计的同时,也深深的被本土品牌的野心和干劲所鼓舞。
今天我们就接着这个背景,开启造车的终极幻想,尝试拆解一下工厂模式中最基础的两部分:简单工厂模式和工厂方法模式。


一言

简单工厂模式:定义一个创建对象的类,由它来封装实例化对象的行为代码。
工厂方法模式:将对象实例化推迟到子类。


为什么要用工厂模式

Wayne造车

如果现在有一个需求,要我们模拟一段造车的代码,你想怎么做?
首先自然是分析需求:

  1. 既然我们要造车,那车的种类必然很多(油车?电车?核动力?!)
  2. 造车的工序我们暂时就粗暴的认为只有准备材料、加工、组装和测试四个步骤
  3. 造好了车,我们还需要通过4S店卖出去

三寸反骨

三条需求刚刚讲完,反骨仔立马站了起来:“这也太简单了!我来!”
于是他这样实现了需求:
首先他清醒的将车做成了抽象:

代码实现(反例)

public abstract class Car {
    protected String name;//名字
    //准备原材料,不同的汽车材料不同,所以做成抽象方法
    public abstract void prepare();
    public void process(){//加工
        System.out.println(name+" processing");
    }
    public void assemble(){//组装
     System.out.println(name+" assemble");
    }
    public void check(){//测试
        System.out.println(name+" check");
    }
    public void setName(String name) {
        this.name = name;
    }
}

然后是车具体的实现:

public class OilCar extends Car{
    @Override
    public void prepare() {
        System.out.println("准备优秀的内燃机");
    }
}
public class EleCar extends Car{
    @Override
    public void prepare() {
        System.out.println("准备优秀耐用的电池");
    }
}

最后是4S店

public class FourS {
    //构造器
    public FourS() {
        Car car = null;
        String orderType;
        do {
            orderType=getType();
            System.out.println("==============================");
           if (orderType.equals("ele")){
               car = new EleCar();
               car.setName("新能源汽车");
           }else if (orderType.equals("oil")){
               car = new OilCar();
               car.setName("燃机汽车");
           }else {
               break;
           }
            car.prepare();
            car.process();
            car.assemble();
            car.check();
        }while (true);
    }

    private String getType(){
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("==============================");
            System.out.println("input car type");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

不得不说,反骨仔确实有所成长,不再是那个100%的毛躁汉子了,但是这种设计是否存在问题?
我们先看下运行的结果:
在这里插入图片描述
业务的实现自然是没有问题的,实现过程也非常容易理解,然后一切的一切发展的都很顺利,我们的车一经上市就大受欢迎,在各方面都是遥遥领先。于是我们决定,扩展业务,“多开几家4S店,再狠狠的赚他一笔,初步预估先开1000家店吧,靓仔啊,你去把这个事情落实一下。奥,对了,你们这个项目现在发展前景非常好,我们已经在和奔驰、宝马、宾利、法拉利等老牌的汽车公司展开了深度合作,以后可能还要把他们的品牌融合到我们的产品中…”。
反骨仔看着自己的代码,汗流浃背了。
可能有的同学已经看到了问题的关键:
在这里插入图片描述
这种设计从根本上违反了OCP原则,每一次小的扩展就会更改大量代码。
有的同学可能会说,我ctrl CV 大法包治百病,那如果我们后面真的在核动力汽车领域有了突破,这部分扩展的代码是不是要改一千多次?
所以说,修改代码并非不可接受,但是如果我们在其它地方也有创建Car,就意味着这些地方都要修改,而创建Car的地方往往有很多处。


基于简单工厂模式的优化

思路分析

好了,我们已经发现了问题下一步就是如何解决这个问题了。
在思路上,我们可以尝试把创建Car对象封装在一个类中,这样我们有新的Car种类时,只需要修改该类即可,其它创建Car对象的代码就不需要修改了。这其实就是简单工厂模式的基本思路。
在这里插入图片描述

核心代码

public class FourS1 {
    Car car = null;
   
    public FourS1(){
        setFactory();
    }
    
    public void setFactory(){
        String orderType="";
        do{
            orderType = getType();
            System.out.println("==============================");
            car = SimpleFactory.createCar(orderType);

            if (car!=null){
                car.prepare();
                car.process();
                car.assemble();
                car.check();
            }else {
                System.out.println("订购汽车失败");
                break;
            }
        }while (true);
    }

    //可以获取客户希望订购的披萨种类
    private String getType(){
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("==============================");
            System.out.println("input pizza type");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

结束了吗

当然没有,我们看似通过简单方法模式解决了大部分的核心问题,但是却忽略了“最新消息”里最致命的那句:“奥,对了,你们这个项目现在发展前景非常好,我们已经在和奔驰、宝马、宾利、法拉利等老牌的汽车公司展开了深度合作,以后可能还要把他们的品牌融合到我们的产品中…”
也就是说,我们后续要求的输出是奔驰的燃机汽车、宝马的燃机汽车、宝马的新能源汽车、奔驰的核动力汽车…
反观简单工厂模式,是否有实力接得住这一波需求?
其实硬要接也不是接不住,无非是多几个SimpleFactory。但是实际操作起来必然很难维护。严格意义上讲,采用简单工厂模式硬接这种需求实际上也是违反OCP原则的。


基于工厂方法模式的优化

思路分析

当与各大品牌合作之后,造车过程似乎变得复杂了起来。首先奔驰和宝马是想和我们合作,而他们之间并没有展开合作,这意味着我们要为他们定制不同的4S店和造车工厂。
在这里插入图片描述

核心代码

public abstract class AbsFourS {
    public abstract Car createPizza(String orderType);

    public AbsFourS() {
        Car car = null;
        String orderType;
        do {
            orderType=getType();
            System.out.println("==============================");

            car=createPizza(orderType);

            car.prepare();
            car.process();
            car.assemble();
            car.check();
        }while (true);
    }

    private String getType(){
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("==============================");
            System.out.println("input car type");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}
public class BenzWayne4s extends AbsFourS {
    @Override
    public Car createPizza(String orderType) {
        Car car = null;
        if(orderType.equals("ele")){
            car = new BenzEleCar();
            car.setName("奔驰与Wayne联名推出的新能源汽车");
        }else if (orderType.equals("oil")){
            car = new BenzOilCar();
            car.setName("奔驰与Wayne联名推出的内燃机汽车");
        }
        return car;
    }
}
public class BmwWayne4s extends AbsFourS {
    @Override
    public Car createPizza(String orderType) {
        Car car = null;
        if(orderType.equals("ele")){
            car = new BMWEleCar();
            car.setName("宝马与Wayne联名推出的新能源汽车");
        }else if (orderType.equals("oil")){
            car = new BMWEleCar();
            car.setName("宝马与Wayne联名推出的内燃机汽车");
        }
        return car;
    }
}

测试结果

在这里插入图片描述
在这里插入图片描述


我们在前面用了大量的篇幅介绍了简单工厂模式和工厂方法模式。记得我在上一篇介绍建造者模式时,卖了个关子,就是关于建造者模式和抽象工厂模式的区别。
抽象工厂模式可以将简单工厂模式和工厂方法模式的优势整合起来,它的理念是基于简单工厂模式和工厂方法模式的,这也正是我花了大量篇幅介绍它们的原因。
抽象工厂模式实现对产品家族的创建,一个产品家族是具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
也就是说:
• 建造者模式比较关注 产品的 “组装过程”;
• 抽象工厂模式只关注什么工厂生产了什么产品;
这一点,在我下周继续拆解抽象工厂模式之后,我们可以一起再来体会一下。


关注我,共同进步,每周至少一更。——Wayne

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1364676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Debezium发布历史49

原文地址: https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/ 欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯. 使用发件箱模式进行可靠的微服务数…

JSP内置对象:forward动作标记和sendRedirect()方法实现页面跳转的区别

1.forward为服务器跳转,浏览器的地址栏不变; sendRedirect()为客户端跳转,浏览器的地址栏改变变新页面的URL。 2.执行到forward标记出现处停止当前JSP页面的继续执行,而转向标记中的page属性指定的页面&am…

【Matplotlib】基础设置之图像处理05

图像基础 导入相应的包: import matplotlib.pyplot as plt import matplotlib.image as mpimg import numpy as np %matplotlib inline导入图像 我们首先导入上面的图像,注意 matplotlib 默认只支持 PNG 格式的图像,我们可以使用 mpimg.im…

一文搞定JVM内存模型

鲁大猿,寻精品资料,帮你构建Java全栈知识体系 www.jiagoujishu.cn 运行时数据区 内存是非常重要的系统资源,是硬盘和 CPU 的中间仓库及桥梁,承载着操作系统和应用程序的实时运行。JVM 内存布局规定了 Java 在运行过程中内存申请、…

56K star!一键拥有跨平台 ChatGPT 应用:ChatGPT-Next-Web

前言 现在围绕 openai 的客户端层出不穷,各路开发大神可以说是各出绝招,我也试用过几个国内外的不同客户端。 今天我们推荐的开源项目是目前我用过最好的ChatGPT应用,在GitHub超过56K Star的开源项目:ChatGPT-Next-Web。 ChatGP…

Java分布式锁理论(redis、zookeeper) 详解

目录 一、分布式锁有哪些应用场景? 二、分布式锁的实现方案 三、zookeeper实现分布式锁 一直不释放锁怎么办? 如何避免分布式锁羊群效应问题? 四、redis实现分布式锁 一、分布式锁有哪些应用场景? 1、定时任务 2、秒杀抢购…

XAgent调研

文章目录 1 简介2 快速测试 Quick Start3 结构分析 1 简介 XAgent(链接)是一个开源的,基于大语言模型的agent构建框架;其目标是构建出能够辅助人类处理各类任务的自动助手 定位:一个全能的,自动的辅助agen…

智邦国际ERP GetPersonalSealData.ashx接口存在SQL注入漏洞 附POC软件

@[toc] 智邦国际ERP GetPersonalSealData.ashx接口存在SQL注入漏洞 附POC软件 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

【普中开发板】基于51单片机的温度报警器LCD1602_可调上下限( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的温度报警器LCD1602_可调上下限 1.主要功能:资料下载链接: 普中开发板实物演示图:2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单 【普中】基于51单片机的温度报警器LCD1602_可调上下限 ( proteus仿真程序设计报告讲解视频&a…

安全基础~信息搜集3

文章目录 知识补充APP信息搜集php开发学习理解漏洞 知识补充 端口渗透总结 python Crypto报错:https://blog.csdn.net/five3/article/details/86160683 APP信息搜集 1. AppInfoScanner 移动端(Android、iOS、WEB、H5、静态网站)信息收集扫描工具 使用教程 演示&…

LCD—液晶显示

本节主要介绍以下内容 显示器简介 液晶控制原理 秉火3.2寸液晶屏简介 使用FSMC模拟8080时序 NOR FLASH时序结构体 FSMC初始化结构体 一、显示器简介 显示器属于计算机的I/O设备,即输入输出设备。它是一种将特定电子信息输出到屏幕上再反射到人眼的显示工具。…

用通俗易懂的方式讲解:使用 Mistral-7B 和 Langchain 搭建基于PDF文件的聊天机器人

在本文中,使用LangChain、HuggingFaceEmbeddings和HuggingFace的Mistral-7B LLM创建一个简单的Python程序,可以从任何pdf文件中回答问题。 一、LangChain简介 LangChain是一个在语言模型之上开发上下文感知应用程序的框架。LangChain使用带prompt和few…

【Spring Boot 源码学习】SpringApplication 的定制化介绍

Spring Boot 源码学习系列 SpringApplication 的定制化介绍 一、引言二、往期内容三、主要内容1. 基础配置1.1 设置关闭 Banner1.2 设置自定义 Banner 打印对象1.3 设置应用程序主入口类1.4 设置用于创建应用程序上下文的工厂1.5 添加 BootstrapRegistry 初始化器实现1.6 设置或…

计算机毕业设计 基于Javaweb的城乡居民基本医疗信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

通俗易懂的15个Java Lambda表达式案例

文章目录 1. **实现Runnable接口**:2. **事件监听器**(如Swing中的ActionListener):3. **集合遍历**(使用forEach方法):4. **过滤集合**(使用Stream API):5. …

VMware17 下载安装教程

VMware17 下载安装ubuntu22.04虚拟机安装 一、VM安装 1.打开官方下载地址:https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html 跳转页面后,点击左边的Download oad now,下载的就是最新版的 Workstation 17 …

Fiber Golang 中的路由和中间件

掌握 GoLang Fiber 中的路由和中间件艺术,以进行高效的 Web 开发 在网络开发领域中,创建一个有效地路由和管理各种任务的 Web 应用程序至关重要。路由决定了如何处理传入的请求,而中间件在执行任务,如身份验证、日志记录和请求解…

【vue】emit 的理解与使用

文章目录 介绍流程示例效果父组件子组件 介绍 $emit 是 Vue 组件实例中的一个方法,用来触发自定义事件,并向父组件传递信息它接受两个参数:事件名称和可选参数this.$emit(事件名称, 参数);流程 示例 效果 触发前 触发后 父组件 父组件使…

stable diffusion 人物高级提示词(五)场景、特效、拍摄手法、风格

一、场景 场景Promptindoor室内outdoor室外cityscape城市景色countryside乡村beach海滩forest森林mountain山脉snowfield雪原skyscraper摩天大楼ancient monument古代遗迹cathedral大教堂library图书馆museum博物馆office building办公大楼restaurant餐厅street market街头市场…

Hive实战:网址去重

文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 (二)实现步骤1、启动Hive Metastore服务2、启动Hive客户端3、基于HDFS数据文件创建Hive外部表4、利用Hive SQL实…