03-JAVA设计模式-工厂模式详解

news2024/11/18 10:30:37

工厂模式

工厂设计模式是一种创建型设计模式,它提供了一种封装对象创建过程的机制,将对象的创建与使用分离。
这种设计模式允许我们在不修改客户端代码的情况下引入新的对象类型。
在Java中,工厂设计模式主要有三种形式:简单工厂模式、工厂方法模式和抽象工厂模式。

简单工厂模式

用来生成同一等级结构中的任意产品。

注:对增加新的产品需要修改已有的代码,这违背了面向对象设计原则中的开闭原则(对扩展开放,对修改关闭)

UML

在这里插入图片描述

实现代码

Animal.java

// 定义一个动物的接口
public interface Animal {

    // 接口中定义一个抽象的方法:叫声
    void makeSound();
}

Cat.java

// 定义一个实现类实现Animal接口
public class Cat implements Animal{
    // 猫属于动物:实现发出叫声的接口
    @Override
    public void makeSound() {
        System.out.println("喵喵喵");
    }
}

Dog.java

// 定义一个实现类实现Animal接口
public class Dog implements Animal{
    // 狗属于动物:实现发出叫声的接口
    @Override
    public void makeSound() {
        System.out.println("汪汪汪");
    }
}

SimpleAnimalFactory.java

// 定义一个简单工厂类用于创建动物
public class SimpleAnimalFactory {
    // 定义一个创建动物的方法用于生产不同的动物的静态方法
    public static Animal createAnimal(String type) {
        if ("Cat".equalsIgnoreCase(type)) {
            return new Cat();
        }
        else if ("Dog".equalsIgnoreCase(type)) {
            return new Dog();
        }
        else  {
           return null;
        }
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        // 根据简单工厂创建不同的动物,执行动作
        // 生产一个Cat
        Animal cat = SimpleAnimalFactory.createAnimal("cat");
        cat.makeSound();
        // 生产一个Dog
        Animal dog = SimpleAnimalFactory.createAnimal("Dog");
        dog.makeSound();
    }
}

执行结果:

在这里插入图片描述

结论:

简单工厂好处在于,对于客户端调用时,我们不需要关心具体实现,只需要调用工厂方法,传入参数获取我们需要返回的结果即可。

但是对于同一个产品(动物),如果我们进行新增(猪),则必须要修改Factory中createAnimal(String type)方法。因此违背了开闭原则

工厂方法模式

用来生产同一等级结构中的固定产品。

支持增加任意产品,满足开闭原则,但设计相对于简单工厂复杂一些

UML

在这里插入图片描述

实现代码

Product.java

// 定义一个产品接口
public interface Product {
    //定义一个抽象的使用的方法
    void use();
}

ProductA.java

// ProductA实现Product接口
public class ProductA implements Product{
    @Override
    public void use() {
        System.out.println("ProductA 使用了");
    }
}

ProductB.java

// ProductB实现Product接口
public class ProductB implements Product{
    @Override
    public void use() {
        System.out.println("ProductB 使用了");
    }
}

ProductFactory.java

// 定义一个ProductFactory工厂接口
public interface ProductFactory {
    // 接口中定义一个创建Product的方法
    Product createProduct();
}

ProductAFactory.java

// 创建一个ProductA的工厂,实现ProductFactory接口,用于生产ProductA
public class ProductAFactory implements ProductFactory{
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

ProductBFactory.java

// 创建一个ProductB的工厂,实现ProductFactory接口,用于生产ProductB
public class ProductBFactory implements ProductFactory{
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        // 创建ProductA
        Product product1 = new ProductAFactory().createProduct();
        product1.use();
        // 创建ProductB
        Product product2 = new ProductBFactory().createProduct();
        product2.use();
    }
}

执行结果:

在这里插入图片描述

从工厂方式模式,我们可以看出,我们可以任意增加同一产品,而不会影响到原来已有产品
(创建一个产品C继承Product接口,创建一个产品C的Factory类生产C,使用是通过相应Factory调用生产C即可)。
如果产品中新增一个方法,则所有实现了Product接口的方法都必须修改相应方法。

抽象工厂模式

用来生产不同产品族的全部产品。

对增加新的产品无能为力,支持增加产品族

UML

在这里插入图片描述

实现代码

Engine.java

// 定义发动机接口
public interface Engine {
    // 定义发动机 发动方法
    void run();
    // 定义发动机 停止方法
    void stop();
}

HighEndEngine.java

// 创建一个高端发动机实现发动机
public class HighEndEngine implements Engine{
    @Override
    public void run() {
        System.out.println("高端发动机-跑的快");
    }
    @Override
    public void stop() {
        System.out.println("高端发动机-刹车性能强");
    }
}

LowEndEngine.java

// 创建一个低端发动机实现发动机
public class LowEndEngine implements Engine{
    @Override
    public void run() {
        System.out.println("低端发动机-跑的慢");
    }
    @Override
    public void stop() {
        System.out.println("低端发动机-刹车性能弱");
    }
}

CarBody.java

// 定义一个车身接口
public interface CarBody {
    // 定义一个乘坐的方法
    void ride();
}

HighEndCarBody.java

// 创建一个高端车身实现车身
public class HighEndCarBody implements CarBody{
    @Override
    public void ride() {
        System.out.println("高端车身-奢华-安全");
    }
}

LowEndCarBody.java

// 创建一个低端车身实现车身
public class LowEndCarBody implements CarBody{
    @Override
    public void ride() {
        System.out.println("低端车身-朴素-看起来安全");
    }
}

Tyre.java

// 定义一个轮胎接口
public interface Tyre {
    // 定义轮胎转动的方法
    void run();
}

HighEndTyre.java

// 创建一个高端轮胎实现轮胎
public class HighEndTyre implements Tyre{
    @Override
    public void run() {
        System.out.println("高端轮胎-太空材料-安全-耐磨");
    }
}

LowEndTyre.java

// 创建一个低端轮胎实现轮胎
public class LowEndTyre implements Tyre{
    @Override
    public void run() {
        System.out.println("低端轮胎-普通材料-易磨损");
    }
}

CarFactory.java

// 定义Car的接口
public interface CarFactory {
    // 创建发动机
    Engine engine();
    // 创建车身
    CarBody carBody();
    // 创建轮胎
    Tyre tyre();
}

HighEndCarBody.java

// 高端汽车工厂实现汽车工厂
public class HighEndCarFactory implements CarFactory{
    @Override
    public Engine engine() {
        return new HighEndEngine();
    }
    @Override
    public CarBody carBody() {
        return new HighEndCarBody();
    }
    @Override
    public Tyre tyre() {
        return new HighEndTyre();
    }
}

LowEndCarFactory.java

// 低端汽车工厂实现汽车工厂
public class LowEndCarFactory implements CarFactory{
    @Override
    public Engine engine() {
        return new LowEndEngine();
    }
    @Override
    public CarBody carBody() {
        return new LowEndCarBody();
    }
    @Override
    public Tyre tyre() {
        return new LowEndTyre();
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        // 使用高端汽车工厂类 创建高端汽车
        HighEndCarFactory highEndCar = new HighEndCarFactory();
        highEndCar.engine().stop();
        highEndCar.carBody().ride();
        highEndCar.tyre().run();

        System.out.println("==========================");

        // 使用低端汽车工厂类 创建低端汽车
        LowEndCarFactory lowEndCar = new LowEndCarFactory();
        lowEndCar.engine().stop();
        lowEndCar.carBody().ride();
        lowEndCar.tyre().run();
    }
}

执行结果:

在这里插入图片描述

抽象工厂,不可以增加产品(比如:CarFactory一旦定下了,如果我们要新增新的部件则所有实现CarFactory的类都需实现该方法)。
但是抽象工厂,可以根据已有的接口,创建更多的产品族(比如:定义一个中端汽车工厂,调用高端发动机,低端轮胎,低端车身,等任意组合成新的Factory)

对比及应用场景

简单工厂模式

  • 优点:
    • 实现了对象的创建和使用的责任分割,客户端只需要传入正确的参数,就可以获取需要的对象,无需知道创建细节。
    • 工厂类中有必要的判断逻辑,可以决定根据当前的参数创建对应的产品实例,客户端可以免除直接创建产品对象的责任。
  • 缺点:
    • 工厂类职责过重,如果产品种类增加,工厂类的代码会变得庞大且复杂,不利于维护。
    • 简单工厂模式违背了开放封闭原则,因为每次增加新产品时,都需要修改工厂类的代码。
  • 适用场景:
    • 创建对象较少,且对象的创建逻辑不复杂时。
    • 客户端不关心对象的创建过程,只关心使用对象时。

工厂方法模式

  • 优点:
    • 将对象的创建推迟到子类中进行,使得类的实例化更加灵活和可扩展。
    • 降低了客户端与具体产品类之间的耦合度,客户端只需要知道对应的工厂,无需知道具体的产品类。
  • 缺点:
    • 增加了系统的抽象性和理解难度,需要引入额外的工厂接口和工厂类。
    • 如果产品类较少,使用工厂方法模式可能会增加不必要的复杂性。
  • 适用场景:
    • 需要创建大量相似对象时,可以使用工厂方法模式来简化对象的创建过程。
    • 当一个类需要由其子类来指定创建哪个对象时,可以使用工厂方法模式。
    • 但实际开发中,简单工厂比工厂方法使用的更多

抽象工厂模式

  • 优点:
    • 提供了创建一系列相关或相互依赖对象的接口,无需指定它们具体的类。
    • 增加了系统的灵活性和可扩展性,可以通过更换不同的工厂来实现不同的产品族。
  • 缺点:
    • 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难。
    • 如果产品族中的产品较少,使用抽象工厂模式可能会导致代码冗余和复杂性增加。
  • 适用场景:
    • 当需要创建一组相互关联或相互依赖的对象时,可以使用抽象工厂模式。
    • 当一个系统需要独立地变化其创建的对象时,抽象工厂模式是一个很好的选择。

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

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

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

相关文章

【CNN】ConvMixer探究ViT的Patch Embedding: Patches Are All You Need?

Patches Are All You Need? 探究Patch Embedding在ViT上的作用,CNN是否可用该操作提升性能? 论文链接:https://openreview.net/pdf?idTVHS5Y4dNvM 代码链接:https://github.com/tmp-iclr/convmixer 1、摘要 ViT的性能是由于T…

基于Spark中随机森林模型的天气预测系统

基于Spark中随机森林模型的天气预测系统 在这篇文章中,我们将探讨如何使用Apache Spark和随机森林算法来构建一个天气预测系统。该系统将利用历史天气数据,通过机器学习模型预测未来的天气情况,特别是针对是否下雨的二元分类问题。 简介 Ap…

【unity】【C#】延时调用(协程)和场景管理

文章目录 什么是协程协程的应用 - IEnumerator如何控制协程的暂停协程的另一种写法 - Invoke场景管理 多看代码块中的注释 什么是协程 A coroutine alows vou to spreacwhere it left off on the following anc return control toolinencoeframe. 协程允许您将任务分布在多个帧…

Android14应用启动流程(源码+Trace)

1.简介 应用启动过程快的都不需要一秒钟,但这整个过程的执行是比较复杂的,无论是对手机厂商、应用开发来说启动速度也是核心用户体验指标之一,本文采用Android14源码与perfetto工具进行解析。 源码参考地址:Search trace分析工…

【二分查找】Leetcode 在排序数组中查找元素的第一个和最后一个位置

题目解析 34. 在排序数组中查找元素的第一个和最后一个位置 我们使用暴力方法进行算法演化,寻找一个数字的区间,我们可以顺序查找,记录最终结果 首先数组是有序的,所以使用二分法很好上手,但是我们就仅仅使用上一道题…

第四百四十二回 再谈flutter_launcher_icons包

文章目录 1. 概念介绍2. 使用方法3. 示例代码4. 经验与总结4.1 经验分享4.2 内容总结 我们在上一章回中介绍了"overlay_tooltip简介"相关的内容,本章回中将 再谈flutter_launcher_icons包.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 …

配置vscode链接linux

1.安装 remote SSH 2.按F1 ssh ljh服务器公网ip 3. 选择保存远端host到本地 某位置 等待片刻后 4. 切换到远程资源管理器中 应该可以看到一台电脑,右键在当前窗口链接,输入你的服务器用户密码后电脑变绿说明远程连接成功 5.一定要登陆上云服务器后再…

Day:004(2) | Python爬虫:高效数据抓取的编程技术(数据解析)

正则表达式实战-腾讯新闻 需求: 使用正则获取腾讯新闻标题内容 网站:https://sports.qq.com/ 代码: import reimport requests from fake_useragent import UserAgenturl https://sports.qq.com/ # 构建请求头信息 headers {User-Agent:…

【JavaWeb】Day33.MySQL概述

什么是数据库 数据库:英文为 DataBase,简称DB,它是存储和管理数据的仓库。 像我们日常访问的电商网站京东,企业内部的管理系统OA、ERP、CRM这类的系统,以及大家每天都会刷的头条、抖音类的app,那这些大家所…

前端学习之DOM编程星星点灯案例

这个案例的实现逻辑是当你点击屏幕时&#xff0c;会完成一个事件&#xff0c;在你的屏幕上生成一张星星图片。然后再设置星星图片的大小将其改为随机。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><t…

K8S基于containerd做容器从harbor拉取镜

实现创建pod时&#xff0c;通过指定harbor仓库里的镜像来运行pod 检查&#xff1a;K8S是不是用containerd做容器运行时&#xff0c;以及containerd的版本是不是小于1.6.22 kubectl get nodes -owide1、如果containerd小于 1.6.22&#xff0c;需要先升级containerd 先卸载旧的…

C/C++预处理过程

目录 前言&#xff1a; 1. 预定义符号 2. #define定义常量 3. #define定义宏 4. 带有副作用的宏参数 5. 宏替换的规则 6. 宏和函数的对比 7. #和## 8. 命名约定 9. #undef 10. 命令行定义 11. 条件编译 12. 头文件的包含 13. 其他预处理指令 总结&#x…

最新高自定义化的AI翻译(沉浸式翻译),可翻译网页和PDF等文件或者文献(附翻译API总结,Deeplx的api,Deepl的api)

前序 常见问题&#xff1a; 1.有时候想翻译网页&#xff0c;又翻译文献怎么办&#xff1f;下两个软件&#xff1f; 2.什么软件可以翻译视频字幕&#xff1f; 3.什么软件可以翻译PDF文件&#xff1f; 沉浸式翻译介绍 可以翻译文献可以翻译视频字幕可以翻译PDF文件支持OpenAI翻译…

7 个 iMessage 恢复应用程序/软件可轻松恢复文本

由于误操作、iOS 升级中断、越狱失败、设备损坏等原因&#xff0c;您可能会丢失 iPhone/iPad 上的 iMessages。意外删除很大程度上增加了这种可能性。更糟糕的是&#xff0c;这种情况经常发生在 iDevice 缺乏备份的情况下。 &#xff08;iPhone消息消失还占用空间&#xff1f;&…

很多名人让人们警惕人工智能,这是为何?

很多名人让人们警惕人工智能的原因可以从多个角度来理解。首先&#xff0c;人工智能作为一个快速发展的领域&#xff0c;具有巨大的潜力和未知性。它涉及到机器学习、深度学习、神经网络等多个复杂的技术领域&#xff0c;而这些技术正日益渗透到我们的日常生活中&#xff0c;从…

JWT/JWS/JWE

JWT(JSON Web Token)&#xff1a;一种基于JSON格式&#xff0c;用于在Web应用中安全传递用户身份验证和授权信息的标准令牌&#xff0c;可以包含签名(JWS)和加密(JWE)的信息 MacAlgorithm(Message Authentication Code Algorithm)&#xff1a;消息认证码算法 HMAC(Hash-based…

【51单片机入门记录】RTC(实时时钟)-DS1302应用

目录 一、DS1302相关写函数 &#xff08;1&#xff09;Write&#xff3f;Ds1302 &#xff08;2&#xff09;Write&#xff3f;Ds1302&#xff3f;Byte 二、DS130相关数据操作流程及相关代码 &#xff08;1&#xff09;DS1302初始化数据操作流程及相关代码 (shijian[i]/10&…

阿里云4核8G服务器ECS通用算力型u1实例优惠价格

阿里云4核8G服务器优惠价格955元一年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云活动链接 aliyunfuwuq…

2023年度总结:允许迷茫,破除迷茫;专注自身,把握当下

0、前言 &#x1f4dc;为什么24年已经过了几个月&#xff0c;才提笔写这年度总结呢&#xff1f;毫不羞愧直问我的内心&#xff0c;其实就是懒罢了。直到前几天朋友看到了我去年写的总结&#xff0c;我自己点进那篇总结&#xff0c;完完整整的看了一遍&#xff0c;又翻看我23年…

C#使用Selenium驱动Chrome浏览器

1.Selenium库依赖安装 Selenium WebDriver是Selenium项目的一部分&#xff0c;用于模拟用户在Web应用程序中的交互操作。它支持多种浏览器&#xff0c;如Chrome、Firefox、IE等&#xff0c;且与各种编程语言&#xff08;如Java、Python、C#等&#xff09;兼容&#xff0c;具有…