Java设计模式 —— 【创建型模式】工厂模式(简单工厂、工厂方法模式、抽象工厂)详解

news2024/11/29 18:48:04

文章目录

  • 前言
  • 一、简单工厂(静态工厂)
      • 1、概述
      • 2、代码实现
      • 3、优缺点
  • 二、工厂方法模式
      • 1、概述
      • 2、代码实现
      • 3、优缺点
  • 三、抽象工厂模式
      • 1、概述
      • 2、代码实现
      • 3、优缺点
  • 四、总结


前言

先看个案例:【手机和手机店】在没有工厂的时候,手机店需要手机就需要自己创建,还得根据用户的选择进行创建不同的手机,如下图:
在这里插入图片描述
这样手机店直接与手机对象接触,就会对该对象耦合严重,假如我们添加新的手机品牌,还得修改手机店的create方法,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,将对象的创建封装在工厂内,实现使用者和对象解耦;所以说,工厂模式最大的优点就是:解耦

工厂模式的主要目的是将对象的创建过程封装在工厂类中,客户端代码只需要关心从工厂获取对象的过程,而不需要了解对象的创建细节。这样可以降低代码的耦合度,提高代码的可维护性和可扩展性


一、简单工厂(静态工厂)

1、概述

简单工厂不是一种设计模式,反而比较像是一种编程习惯。把对象的创建和业务逻辑层分开,实现使用方(手机店)与对象(手机)的解耦。但工厂和产品之间还是存在耦合关系。

主要包含以下角色:

  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品: 实现或者继承抽象产品的子类
  • 具体工厂: 提供了创建产品的方法,调用者通过该方法来获取产品。
    在这里插入图片描述

2、代码实现

抽象手机类【抽象产品】:

public abstract class Phone {
    public abstract String getName();
}

手机产品【具体产品】:

public class  HuaWei extends Phone {
    @Override
    public String getName() {
        return "华为手机";
    }
}

public class XiaoMi extends Phone {
    @Override
    public String getName() {
        return "小米手机";
    }
}

手机工厂【具体工厂】:

public class Factory {
    public static Phone createPhone(String name) {
        Phone phone = null;
        if("小米".equals(name)) {
            phone = new XiaoMi();
        } else if("华为".equals(name)) {
            phone = new HuaWei();
        }
        return phone;
    }
}

手机店【使用者】:

public class Sotre {
    public static Phone orderPhone(String name) {
        return Factory.createPhone(name);
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        Phone xiaomi = Sotre.orderPhone("小米");
        System.out.println(xiaomi.getName());
        Phone huawei = Sotre.orderPhone("华为");
        System.out.println(huawei.getName());
    }
}

在这里插入图片描述

3、优缺点

优点:

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

缺点:

增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。


二、工厂方法模式

1、概述

在在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体的工作交给子类去做。 定义一个用于创建对象的接口(抽象工厂),让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。很好的解决了简单工厂的问题,遵循开闭原则。

工厂方法模式的主要角色:

  • 抽象工厂: 提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂: 主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

在这里插入图片描述

2、代码实现

抽象手机类【抽象产品】:

public abstract class Phone {
    public abstract String getName();
}

手机产品【具体产品】:

//小米手机
public class XiaoMi extends Phone {
    @Override
    public String getName() {
        return "小米手机";
    }
}

//华为手机
public class HuaWei extends Phone {
    @Override
    public String getName() {
        return "华为手机";
    }
}

抽象工厂:

class interface PhoneFactory {
    Phone createPhone();
}

具体工厂:

//小米工厂
public class XiaoMiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new XiaoMi();
    }
}

//华为工厂
public class HuaWeiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new HuaWei();
    }
}

手机店【使用者】:

public class Store {
    public Phone orderPhone(PhoneFactory factory) {
        return factory.createPhone();
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        Store store = new Store();
        Phone huaWei = store.orderPhone(new HuaWeiFactory());
        Phone xiaomi = store.orderPhone(new XiaoMiFactory());

        System.out.println(xiaomi.getName());
        System.out.println(huaWei.getName());
    }
}

在这里插入图片描述

3、优缺点

优点:

  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;

缺点:

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

三、抽象工厂模式

1、概述

抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产同一个等级的产品(小米手机,华为手机),而抽象工厂模式可生产多个等级的产品(小米家族,华为家族)。
在这里插入图片描述
抽象工厂模式的主要角色如下:

  • 抽象工厂: 提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品(小米工厂和华为工厂的所有功能的抽象【创建手机,创建路由器】)。
  • 具体工厂: 主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建(小米工厂造小米家族产品,华为工厂造华为家族产品)。
  • 抽象产品: 定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品(小米和华为所拥有的同一系列产品的抽象【手机产品,路由器产品】)。
  • 具体产品: 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

在这里插入图片描述

2、代码实现

抽象工厂:

public interface Factory {
    // 生产手机
    Phone createPhone();
    // 生产路由器
    Router createRouter();
}

具体工厂:

//小米工厂
public class XiaoMiFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new XiaoMiPhone();
    }
    @Override
    public Router createRouter() {
        return new XiaoMiRouter();
    }
}

//华为工厂
public class HuaWeiFactory implements Factory {
    @Override
    public Phone createPhone() {
        return new HuaWeiPhone();
    }
    @Override
    public Router createRouter() {
        return new HuaWeiRouter();
    }
}

抽象产品:

//手机产品
public abstract class Phone {
    public abstract String getName();
}

//路由器类
public abstract class Router {
    public abstract String getName();
}

具体产品:

public class XiaoMiPhone extends Phone{
    @Override
    public String getName() {
        return "小米手机";
    }
}

public class HuaWeiPhone extends Phone {
    @Override
    public String getName() {
        return "华为手机";
    }
}
public class XiaoMiRouter extends Router {
    @Override
    public String getName() {
        return "小米路由器";
    }
}

public class HuaWeiRouter extends Router {
    @Override
    public String getName() {
        return "华为路由器";
    }
}

手机店:

public class Store {
    private Factory factory;
    public void setFactory(Factory factory) {
        this.factory = factory;
    }
    public Phone orderPhone(){
         return factory.createPhone();
    }
    public Router orderRouter(){
        return factory.createRouter();
    }
}

测试:

public class Test {
    public static void main(String[] args) {
        Store store = new Store();
        store.setFactory(new XiaoMiFactory());
        Phone xiaomiPhone = store.orderPhone();
        Router xiaomiRouter = store.orderRouter();
        System.out.println(xiaomiPhone.getName());
        System.out.println(xiaomiRouter.getName());
        System.out.println("===========");
        store.setFactory(new HuaWeiFactory());
        Phone huaweiPhone = store.orderPhone();
        Router huaweiRouter = store.orderRouter();
        System.out.println(huaweiPhone.getName());
        System.out.println(huaweiRouter.getName());
    }
}

在这里插入图片描述
如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类。

3、优缺点

优点:

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:

当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。


四、总结

  1. 以上述案例为例,没有工厂就是手机店直接造手机,使用者和对象高度耦合,新增品类时违背开闭原则,一个手机店造不同手机违背单一职责原则;
  2. 由此引出简单工厂,手机店只需要和工厂打交道,售卖手机,不负责造手机的过程,实现手机店和对象的解耦,但是工厂和对象还是存在上述问题;
    在这里插入图片描述
  3. 由此工厂在向上抽象出“工厂规范”,形成工厂方法模式,不同的工厂负责不同的职责,添加新的品类时增加对应工厂和产品即可;
    在这里插入图片描述
  4. 在往下走,工厂做大做强以后,不只是可以生产手机,还添加了新的产品路由器,形成抽象工厂模式。
    在这里插入图片描述
  5. 工厂方法模式是针对单一的品类进行的实现,二抽象工厂是针对多个品类(产品族)的实现。

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

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

相关文章

利用Java爬虫获取阿里巴巴中国站跨境属性的详细指南

在全球化贸易的浪潮中,跨境电商正成为连接全球买家和卖家的重要桥梁。阿里巴巴中国站作为全球领先的B2B电子商务平台,提供了海量的商品信息,其中跨境属性信息对于跨境电商尤为重要。本文将详细介绍如何使用Java编写爬虫,从阿里巴巴…

「Qt Widget中文示例指南」如何为窗口实现流程布局?(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。 本文将展示如何为不…

鸿蒙学习使用模拟器运行应用(开发篇)

文章目录 1、系统类型和运行环境要求2、创建模拟器3、启动和关闭模拟器4、安装应用程序包和上传文件QA:在Windows电脑上启动模拟器,提示未开启Hyper-V 1、系统类型和运行环境要求 Windows 10 企业版、专业版或教育版及以上,且操作系统版本不低于10.0.18…

Java后端如何进行文件上传和下载 —— 本地版

简介: 本文详细介绍了在Java后端进行文件上传和下载的实现方法,包括文件上传保存到本地的完整流程、文件下载的代码实现,以及如何处理文件预览、下载大小限制和运行失败的问题,并提供了完整的代码示例。 大体思路 1、文件上传 …

SqlServer强制转换函数TRY_CONVERT和TRY_CAST

SqlServer强制转换函数TRY_CONVERT和TRY_CAST的介绍和案例分享 1、本节内容 CAST 和 CONVERT TRY_CAST TRY_CONVERT 适用于: SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse Analytics 分析平台系统 (PDW)Microsoft Fabric 中的 SQL 分析端点Micro…

透视投影(Perspective projection)与等距圆柱投影(Equirectangular projection)

一、透视投影 1.方法概述 Perspective projection(透视投影)是一种模拟人眼观察三维空间物体时的视觉效果的投影方法。它通过模拟观察者从一个特定视点观察三维场景的方式来创建二维图像。在透视投影中,远处的物体看起来比近处的物体小&…

linux 中后端jar包启动不起来怎么回事 -bash: java: 未找到命令

一、用以下命令检查jdk版本 输入:java -version,如果JDK 环境变量没有配置,你会看到如下提示 二、配置jdk环境 1.先找到/etc/profile文件,然后在该文件最后面加上以下配置 export JAVA_HOME/usr/local/jdk-21.0.1 export PATH$…

TDengine在debian安装

参考官网文档&#xff1a; 官网安装文档链接 从列表中下载获得 Deb 安装包&#xff1b; TDengine-server-3.3.4.3-Linux-x64.deb (61 M) 进入到安装包所在目录&#xff0c;执行如下的安装命令&#xff1a; sudo dpkg -i TDengine-server-<version>-Linux-x64.debNOTE 当…

Java开发工程师最新面试题库系列——Java基础部分(附答案)

如果你有更好的想法请在评论区留下您的答案&#xff0c;一起交流讨论# 面向对象有哪些特征&#xff1f; 答&#xff1a;继承、封装、多态 JDK与JRE的区别是什么&#xff1f; 答&#xff1a;JDK是java开发时所需环境&#xff0c;它包含了Java开发时需要用到的API&#xff0c;JRE…

linux系统下如何将xz及ISO\img等格式压缩包(系统)烧写到优盘(TF卡)

最近用树莓派做了个NAS&#xff0c;效果一般&#xff0c;缺少监控及UI等&#xff0c;详细见这篇文章&#xff1a; https://blog.csdn.net/bugsycrack/article/details/135344782?spm1001.2014.3001.5501 所以下载了专门的基于树莓派的NAS系统直接使用。这篇文章是顺便复习一…

计算机的错误计算(一百六十八)

摘要 算式“(5^25*(1/25)^(1/5)*3^25(1/25)^(1/5)*5^25*3^(251/5)-(9/25)^(1/5)*3^25*5^25-(1/25)^(1/5)*3^25*5.0^25*(13^(1/5)-3^(2/5.0)))”的值为0。但是&#xff0c;在 MATLAB 中计算它&#xff0c;则输出含有15位整数。 例1. 计算 直接贴图吧&#xff1a; 这样&#x…

Python学习------第十四天

匿名函数 1.函数作为参数来传递 &#xff08;函数的参数中调用另外一个函数&#xff09; #定义一个函数&#xff0c;接受另一个函数作为参数传入 #计算逻辑的传入 def test_func(compute):result compute(1,2)print(result)print(f"{type(result)}")print(f"…

【经典论文阅读】Transformer(多头注意力 编码器-解码器)

Transformer attention is all you need 摘要 完全舍弃循环 recurrence 和卷积 convolutions 只依赖于attention mechanisms 【1】Introduction 完全通过注意力机制&#xff0c;draw global dependencies between input and output 【2】Background 1&#xff1a;self-…

Java——多线程案例

目录 一、单例模式 1.饿汉模式 2.懒汉模式 3.线程安全问题 4.解决线程安全问题(懒汉模式) 二、阻塞式队列 1.什么是阻塞队列 2.生产者消费模型 生产者消费者模型意义&#xff1a; 1.解耦合 2.削峰填谷 3.标准库中的阻塞队列 三、定时器 1.定时器是什么 2.标准库中的…

AI 声音:数字音频、语音识别、TTS 简介与使用示例

在现代 AI 技术的推动下&#xff0c;声音处理领域取得了巨大进展。从语音识别&#xff08;ASR&#xff09;到文本转语音&#xff08;TTS&#xff09;&#xff0c;再到个性化声音克隆&#xff0c;这些技术已经深入到我们的日常生活中&#xff1a;语音助手、自动字幕生成、语音导…

Linux服务器安装mongodb

因为项目需要做评论功能&#xff0c;领导要求使用mongodb&#xff0c;所以趁机多学习一下。 在服务器我们使用docker安装mongodb 1、拉取mongodb镜像 docker pull mongo &#xff08;默认拉取最新的镜像&#xff09; 如果你想指定版本可以这样 docker pull mongo:4.4&#…

Java基础 设计模式——针对实习面试

目录 Java基础 设计模式单例模式工厂模式观察者模式策略模式装饰器模式其他设计模式 Java基础 设计模式 单例模式 单例模式&#xff08;Singleton Pattern&#xff09; 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问这个实例。适用场景&…

分布式搜索引擎之elasticsearch单机部署与测试

分布式搜索引擎之elasticsearch单机部署与测试 1.部署单点es 1.1.创建网络 因为我们还需要部署kibana容器&#xff0c;因此需要让es和kibana容器互联。这里先创建一个网络&#xff1a; docker network create es-net1.2.加载镜像 这里我们采用elasticsearch的7.12.1版本的…

【工具】JS解析XML并且转为json对象

【工具】JS解析XML并且转为json对象 <?xml version1.0 encodingGB2312?> <root><head><transcode>hhhhhhh</transcode></head><body><param>ccccccc</param><param>aaaaaaa</param><param>qqqq<…

CSDN设置成黑色背景(谷歌 Edge)

一.谷歌浏览器 浏览器地址输入&#xff1a;Chrome://flags搜索框输入&#xff1a;enable-force-dark将default 改成 enabled&#xff0c;点击重启浏览器 二.Edge浏览器 浏览器地址输入&#xff1a;edge://flags搜索里面输入Auto Dark Mode for Web Contents将default 改成 e…