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

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

在这里插入图片描述
最近小米新车亮相的消息可以说引起了不小的轰动,我们在感慨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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

web左侧伸缩菜单栏/导航栏

效果展示&#xff1a; 百度网盘链接下载全部资源&#xff1a; http://链接&#xff1a;https://pan.baidu.com/s/1ZnKdWxTH49JhqZ7Xd-cJIA?pwd4332 提取码&#xff1a;4332 html/JQuery代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head&g…

垂直领域大模型——文档图像大模型的思考与探索

〇、前言 12月1日&#xff0c;2023中国图象图形学学会青年科学家会议在广州召开。超1400名研究人员齐聚一堂&#xff0c;进行学术交流与研讨&#xff0c;共同探索促进图象图形领域“产学研”交流合作。 大会上&#xff0c;合合信息智能技术平台事业部副总经理、高级工程师丁凯博…

UE5 C++(十一)— 碰撞检测

文章目录 代理绑定BeginOverlap和EndOverlapHit事件的代理绑定碰撞设置 代理绑定BeginOverlap和EndOverlap 首先&#xff0c;创建自定义ActorC类 MyCustomActor 添加碰撞组件 #include "Components/BoxComponent.h"public:UPROPERTY(VisibleAnywhere, BlueprintRea…

UG装配-爆炸图

当我们将零件装配成总成的时候&#xff0c;通常需要绘制爆炸图来说明总成零件组成&#xff0c;需要用到爆炸图命令&#xff0c;首先点击新建爆炸&#xff0c;然后为爆炸图命名 然后我们可以选择编辑爆炸或者自动爆炸&#xff1a; 编辑爆炸是通过手动的方式选择部件&#xff0c…

CentOS 7 基于官方源码和openssl制作openssh 9.6 rpm包(含ssh-copy-id) —— 筑梦之路

之前写了一篇&#xff1a; CentOS 7 制作openssh 9.6 rpm包更新修复安全漏洞 —— 筑梦之路_升级openssh9.6-CSDN博客 有好几个网友反馈&#xff0c;ssh-keygen生成密钥存在问题&#xff0c;之前的rsa \ dsa加密算法用不了&#xff0c;因此写了一篇&#xff1a; 关于openssh…

华为OD机试 - 反射计数(Java JS Python C)

题目描述 给定一个包含 0 和 1 的二维矩阵。 给定一个初始位置和速度,一个物体从给定的初始位置出发,在给定的速度下进行移动,遇到矩阵的边缘则发生镜面发射。 无论物体经过 0 还是 1,都不影响其速度。 请计算并给出经过 t 时间单位后,物体经过 1 点的次数。 矩阵以左…

JVM,Java堆区、新生代、老年代,创建对象的内存分配,分代垃圾收集思想、堆区产生的错误

JVM堆区 堆&#xff08;Heap&#xff09;堆区的组成&#xff1a;新生代老年代堆空间的大小设置创建对象的内存分配堆区的分代垃圾收集思想堆区产生的错误 堆&#xff08;Heap&#xff09; ​ Heap堆区&#xff0c;用于存放对象实例和数组的内存区域 ​ Heap堆区&#xff0c;是…

如何写一篇专利?格式与要求

如何写一篇专利&#xff1f;格式与要求 知识产权专利类型发明实用新型外观设计 专利的审查专利授权的标准新颖性创造性实用性 不授予专利的情形 专利的挖掘专利五书权力要求书说明书技术领域背景技术发明内容附图说明具体实施方式 说明书附图说明书摘要摘要附图 知识产权 市场…

使用 Windows 调试器查找 GDI 泄漏

文章目录 介绍为什么!htrace命令无法使用?总结附:GDI使用的几个注意点:本文将带您了解如何使用 Windows 调试器跟踪 GDI 句柄泄漏,并了解如何修复它们。 介绍 本文是有关使用 Windows 调试器查找和修复 GDI 句柄泄漏的演练。Windows调试器应该是最后的手段,首先在整个代…

基于sigma-delta和MASHIII调制器的频率合成器simulink建模与仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 Sigma-Delta调制器原理 4.2 数学模型 4.3 噪声整形 4.4 MASH III调制器原理 4.5 基于Sigma-Delta和MASH III的频率合成器 5.算法完整程序工程 1.算法运行效果图预览 其误差当系统进…

ELK的搭建—Elasticsearch-8.11.3的安装及集群的搭建

es的安装及其集群的搭建 一、Elasticsearch服务的安装部署1. Elasticsearch的rpm包下载2. 安装Elasticsearch服务3. 设置系统资源及内存大小分配4. Elasticsearch的配置修改 二、建立Elasticsearch集群1. 安装Elasticsearch主节点server12. 配置server1&#xff0c;及配置文件的…

python实现目录和文件管理

目录 一&#xff1a;模块介绍&#xff1a; 二&#xff1a;目录创建 三&#xff1a;目录删除 四&#xff1a;目录复制 五&#xff1a;目录移动 六&#xff1a;文件创建 七&#xff1a;文件删除 八&#xff1a;文件读取 一&#xff1a;模块介绍&#xff1a; Python的os和…

《2024 AIGC 应用层十大趋势白皮书》:近屿智能OJAC带您一起探索AI未来

Look&#xff01;&#x1f440;我们的大模型商业化落地产品&#x1f4d6;更多AI资讯请&#x1f449;&#x1f3fe;关注Free三天集训营助教在线为您火热答疑&#x1f469;&#x1f3fc;‍&#x1f3eb; 近日国际知名咨询机构IDC发布《2024 AIGC 应用层十大趋势白皮书》的发布&am…

熟悉HBase常用操作

1. 用Hadoop提供的HBase Shell命令完成以下任务 (1)列出HBase所有表的相关信息,如表名、创建时间等。 启动HBase: cd /usr/local/hbase bin/start-hbase.sh bin/hbase shell列出HBase所有表的信息: hbase(main):001:0> list(2)在终端输出指定表的所有记录数据。 …

音频文件元数据:批量修改技巧,视频剪辑高效修改元数据的方法

随着数字媒体技术的快速发展&#xff0c;音频文件已成为日常生活中的重要组成部分。无论是音乐、语音还是其他音频内容&#xff0c;元数据都是描述这些文件的重要信息。下面来看下云炫AI智剪如何批量修改音频文件元数据&#xff0c;在视频剪辑中高效修改元数据的方法。 下面来看…

阿里开源AnyText:可在图像中生成任意精准文本,支持中文!

‍随着Midjourney、Stable Difusion等产品的出现&#xff0c;文生图像领域获得了巨大突破。但是想在图像中生成/嵌入精准的文本却比较困难。 经常会出现模糊、莫名其妙或错误的文本&#xff0c;尤其是对中文支持非常差&#xff0c;例如&#xff0c;生成一张印有“2024龙年吉祥…

校招社招,认知能力测验,③如何破解语言常识类测试题?

作为认知能力测评中的一个环节&#xff0c;语言常识类&#xff0c;是大概率的出现&#xff0c;不同的用人单位可能略有不同&#xff0c;语言是一切的基础&#xff0c;而常识则意味着我们的知识面的宽度。 语言常识类的测试&#xff0c;如果要说技巧&#xff1f;难说....更多的…

IPv6路由协议---IPv6动态路由(RIPng)

IPv6动态路由协议 动态路由协议有自己的路由算法,能够自动适应网络拓扑的变化,适用于具有一定数量三层设备的网络。缺点是配置对用户要求比较高,对系统的要求高于静态路由,并将占用一定的网络资源和系统资源。 路由表和FIB表 路由器转发数据包的关键是路由表和FIB表,每…

AI变现项目:刚做五天收益突破单日破50+,干货经验谈

今日是我单号操作的第五天。 打开今日头条&#xff0c;发现收益破新高了。 我这是一个号操作&#xff0c;10个号&#xff0c;20个号呢&#xff1f; 下面主要说说我的操作经验。 先确定领域 我是做的情感故事领域。 为什么做这个领域&#xff1f;(简单&#xff0c;原创度高…

计算机视觉技术-语义分割

讨论的目标检测问题中&#xff0c;我们一直使用方形边界框来标注和预测图像中的目标。 本节将探讨语义分割&#xff08;semantic segmentation&#xff09;问题&#xff0c;它重点关注于如何将图像分割成属于不同语义类别的区域。 与目标检测不同&#xff0c;语义分割可以识别并…