【Java开发】设计模式 02:工厂模式

news2024/11/24 22:49:28

1 工厂模式介绍

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

1.1 场景

  • 目的:使用工厂代替new操作,使代码结构清晰,有效地封装变化;

  • 适用:在任何需要生成复杂对象的地方,都可以使用工厂方法模式

  1. 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

  1. 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

  1. 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。

  • 优点

  1. 一个调用者想创建一个对象,只要知道其名称就可以了。

  1. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

  1. 屏蔽产品的具体实现,调用者只关心产品的接口。

  • 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

根据迪米特法则,应该尽可能地少与其他类进行交互,所以可以将那些需要频繁出现的对象创建,封装到一个工厂类中。当需要对象时,直接调用工厂类中的工厂方法来生成对象,这样,就算类出现了变动,只需要修改工厂中的代码即可,而不是大面积地进行修改。同时,可能某些对象的创建并不只是一个 new 就可以搞定,可能还需要更多的步骤来准备构造方法需要的参数。

1.2 简单工厂模式实现

简单工厂其实不是一个标准的的设计模式。GOF 23 种设计模式中只有「工厂方法模式」与「抽象工厂模式」。简单工厂模式可以看为工厂方法模式的一种特例,为了统一整理学习,就都归为工厂模式。

下面以水果工厂生产水果为例介绍普通工厂模式:

📌 1.定义水果类

//水果类
public class Fruit {

    private final String name;

    public Fruit(String name){
        this.name = name;
    }
}

📌 2.定义苹果类和橙子类

//苹果类
public class Apple extends Fruit{

    public Apple() {
        super("苹果");
    }
}
//橙子类
public class Orange extends Fruit{

    public Orange() {
        super("橙子");
    }
}

📌 3.定义水果工厂

//水果工厂
public class FruitFactory{

    /**
     * 这里就直接使用静态方法根据指定类型进行创建
     * @param type 水果类型
     * @return 对应的水果对象
     */
    public static Fruit getFruit(String type){
        switch (type){
            case "苹果":
                return new Apple();
            case "橙子":
                return new Orange();
            default:
                return null;
        }
    }
}

📌 4.调用

// 直接问工厂要,而不是自己去创建
Apple apple = (Apple) FruitFactory.getFruit("苹果");
Orange orange = (Orange) FruitFactory.getFruit("橙子");

📢 总结

工厂类是整个简单工厂模式的关键。包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的。明确了各自的职责和权利,有利于整个软件体系结构的优化。

不过这样还是有一些问题,比如开闭原则,一个软件实体,比如类、模块和函数应该对扩展开放,对修改关闭。此时如果需要新增一种水果,比如桃子,那么就得去修改工厂提供的工厂方法了,这样是不太符合开闭原则的。因为工厂实际上是针对于调用方提供的,所以应该尽可能对修改关闭。

2 工厂方法模式

我们就利用对扩展开放,对修改关闭的性质,将简单工厂模式改进为工厂方法模式,既然不让改,那么就看看如何去使用扩展的形式。

这里还是以水果工厂生产水果介绍工厂方法模式:

📌 1.定义水果工厂

import com.yinyu.study.factory.simple.Fruit;

/**
 * 水果工厂
 * <p>将水果工厂抽象为抽象类,添加泛型 T 由子类指定水果类型
 */
public abstract class FruitFactory<T extends Fruit> {

    /**
     * 不同的水果工厂,通过此方法生产不同的水果
     * @return 水果对象
     */
    public abstract T getFruit();
}

📌 2.定义苹果工厂和橙子工厂

import com.yinyu.study.factory.simple.Apple;

public class AppleFactory extends FruitFactory<Apple>{

    /**
     * 获取苹果对象
     * @return 苹果对象
     */
    @Override
    public Apple getFruit() {
        return new Apple();
    }
}
import com.yinyu.study.factory.simple.Orange;

public class OrangeFactory extends FruitFactory<Orange>{

    /**
     * 获取橙子对象
     * @return 橙子对象
     */
    @Override
    public Orange getFruit() {
        return new Orange();
    }
}

这样,就可以使用不同类型的工厂来生产不同类型的水果了,如果新增了水果类型,直接创建一个新的工厂类就行,不需要修改之前已经编写好的内容。

📌 3.调用

// 使用对应的工厂生产对应的对象
Apple apple = new AppleFactory().getFruit();
Orange orange = new OrangeFactory().getFruit();

这样实现了工厂方法模式,通过工厂来屏蔽对象的创建细节,使用者只需要关心如何去使用对象即可。

📢 总结

由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

3 抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类,抽象工厂(Abstract Factory)模式,又称工具箱(Kit 或 Toolkit)模式。

这里以云南工厂生产水果介绍抽象工厂模式:

📌 1.定义香蕉和芒果接口

public interface Banana {

    void bananaInfo();
}
public interface Mango {

    void mangoInfo();
}

📌 2.定义云南香蕉和云南芒果工厂

public class YunnanBanana implements Banana{

    @Override
    public void bananaInfo() {
        System.out.println("云南香蕉");
    }
}
public class YunnanMango implements Mango{

    @Override
    public void mangoInfo() {
        System.out.println("云南芒果");
    }
}

📌 3.定义工厂接口生产香蕉和芒果

public interface Factory {

    Banana proBanana();

    Mango proMango();
}

📌 4.定义云南工厂类实现工厂接口

public class YunnanFactory implements Factory{

    @Override
    public Banana proBanana() {
        return new YunnanBanana();
    }

    @Override
    public Mango proMango() {
        return new YunnanMango();
    }
}

📌 5.调用

Factory factory = new YunnanFactory();

YunnanBanana banana = (YunnanBanana) factory.proBanana();
YunnanMango mango = (YunnanMango) factory.proMango();

banana.bananaInfo();
mango.mangoInfo();

📢 总结

云南工厂类似一个产品族,它可以生产云南香蕉和云南芒果,那么也可以很方便地创建一个广西工厂,用来生产广西香蕉和广西芒果;不过倘若各工厂要生产一件新的水果,那么工厂接口和各具体工厂都将进行修改,如此会造成较大麻烦。

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

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

相关文章

Weblogic管理控制台未授权远程命令执行漏洞复现(cve-2020-14882/cve-2020-14883)

目录漏洞描述影响版本漏洞复现权限绕过漏洞远程命令执行声明&#xff1a;本文仅供学习参考&#xff0c;其中涉及的一切资源均来源于网络&#xff0c;请勿用于任何非法行为&#xff0c;否则您将自行承担相应后果&#xff0c;本人不承担任何法律及连带责任。 漏洞描述 Weblogic…

CorelDRAW2023最新版新增功能200多个新模板

CorelDRAW是一款平面矢量绘图排版软件&#xff0c;CorelDRAW运用涵盖企业VI设计&#xff0c;广告设计&#xff0c;包装设计&#xff0c;画册设计&#xff0c;海报、招贴设计&#xff0c;UI界面设计&#xff0c;网页设计&#xff0c;书籍装帧设计&#xff0c;插画设计&#xff0…

韩信点兵问题,鸡兔同笼问题,闰年判断问题等,我用Python瞬间搞定(13)

小朋友们好&#xff0c;大朋友们好&#xff01;我是猫妹&#xff0c;一名爱上Python编程的小学生。欢迎和猫妹一起&#xff0c;趣味学Python。今日主题最近猫妹一直在练习Python编程&#xff0c;有些习题真是经典啊&#xff01;比如韩信点兵问题&#xff0c;比如鸡兔同笼问题等…

【Linux】线程实例 | 简单线程池

今天来写一个简单版本的线程池 1.啥是线程池 池塘&#xff0c;顾名思义&#xff0c;线程池就是一个有很多线程的容器。 我们只需要把任务交到这个线程的池子里面&#xff0c;其就能帮我们多线程执行任务&#xff0c;计算出结果。 与阻塞队列不同的是&#xff0c;线程池中内有…

代码随想录刷题-数组-螺旋矩阵II

文章目录螺旋矩阵 II习题我的解法别人的解法螺旋矩阵 II 本节对应代码随想录中&#xff1a;代码随想录&#xff0c;讲解视频&#xff1a;一入循环深似海 | LeetCode&#xff1a;59.螺旋矩阵II_哔哩哔哩_bilibili 习题 题目链接&#xff1a;59. 螺旋矩阵 II - 力扣&#xff0…

将spring boot项目打包成一个可执行的jar包

将spring boot项目打包成一个可执行的jar包&#xff0c;jar包自带了整个运行环境简化配置&#xff0c;可直接运行&#xff0c;本次使用HelloWorld项目演示。 创建Spring Boot项目在pom.xml中导入插件 <build><plugins><plugin><groupId>org.springfr…

计算机网络:移动IP

移动IP相关概念 移动IP技术是移动结点&#xff08;计算机/服务器&#xff09;以固体的网络IP地址&#xff0c;实现跨越不同网段的漫游功能&#xff0c;并保证了基于网络IP的网络权限在漫游中不发生任何改变。移动结点&#xff1a;具有永久IP地址的设备。归属代理&#xff08;本…

西瓜播放器全屏功能源码分析

H5业务中使用了西瓜播放器&#xff0c;嵌入各个APP&#xff0c;全屏时候会有相应的差异。带着好奇心&#xff0c;阅读一下xgpplayer全屏功能部分源代码。源码地址一、工具方法其他方法看名称就知道是dom操作相关&#xff0c;无需多说&#xff0c;上面这两个工具方法主要用来检测…

数学建模资料整理

数学建模中有三类团队&#xff1a; 第一类&#xff1a;拿到题目&#xff0c;讨论&#xff0c;然后建模手开始建模&#xff0c;编程手开始处理数据&#xff0c;写作手开始写作。 第二类&#xff1a;拿到题目&#xff0c;团内大佬&#xff0c;开始建模&#xff0c;然后编程&#…

【GAOPS055】verilog 乘法、除法和取余

乘法硬件原理结论思路1思路2举例编码仿真综合除法硬件原理verilog代码仿真结果资源占用乘法硬件原理 结论 可以将乘法A x B转为A的移位相加。 利用乘2n就是左移n位的特性乘2^n就是左移n位的特性乘2n就是左移n位的特性&#xff0c;将数拆分为2n2^n2n表示 思路1 原始列竖式计…

【C++】通过priority_queue、reverse_iterator加深对于适配器和仿函数的理解

苦尽甘来 文章目录一、仿函数&#xff08;仿函数就是一个封装()运算符重载的类&#xff09;1.C语言的函数指针2.C的仿函数对象二、priority_queue中的仿函数1.模拟实现优先级队列1.1 优先级队列的本质&#xff08;底层容器为vector的适配器&#xff09;1.2 向下调整算法建堆1.3…

git添加子模块(submodule)

git添加子模块(submodule) 背景 有时候自己的项目需要用到别人的开源代码&#xff0c;例如 freertos 和 tinyusb 这个时候有两种选择 将开源的代码下载下来放到自己的 git 中管理 缺点&#xff1a;如果远端仓库更新&#xff0c;自己仓库的代码不会更新 将开源代码通过子模块…

2023河北沃克HEGERLS甘肃金昌重型仓储项目案例|托盘式四向穿梭车智能密集存储系统在工业行业的创新应用

项目名称&#xff1a;自动化仓储托盘式四向穿梭车智能密集立体库项目 项目合作客户&#xff1a;甘肃省金昌市某集团企业 项目施工地域&#xff1a;甘肃省金昌市 设计与承建单位&#xff1a;河北沃克金属制品有限公司&#xff08;自主品牌&#xff1a;海格里斯HEGERLS&#x…

Mysql的Explain关键字

引入 MySQL为我们提供了 explain 关键字来直观的查看一条SQL的执行计划 概念 1.id SELECT识别符&#xff0c;这是SELECT的查询序列号 2.select_type 查询类型 SIMPLE:简单SELECT(不使用UNION或子查询) PRIMARY:最外面的SELECT UNION:UNION中的第二个或后面的SELECT语句 DEPEND…

你的游戏帐号是如何被盗的

据报道&#xff0c;2022上半年&#xff0c;中国游戏市场用户规模达到了5.54亿人&#xff0c;游戏市场销售收入1163.1亿元&#xff0c;相较去年均为同比增长的情况。如此庞大的市场规模&#xff0c;黑色产业链是绕不开的话题。 但相较于游戏中大家常见的玩家与玩家、玩家与官方…

一维连续型随机变量函数的分布例题(一)

设随机变量X的概率密度为&#xff0c;求Y2X8的概率密度。 令g(x)Y&#xff0c;即g(x)2X8。我们可以得到Y的值域为(8,16)。 方法一&#xff1a;看看Y是不是单调可导的函数 此处Y单调可导。 然后求Y的反函数&#xff0c;即。再对h(x)求导可得。 再由公式我们可得 再补上定义域…

[洛谷-P1273]有线电视网(树形DP + 分组背包DP)

[洛谷-P1273]有线电视网&#xff08;树形DP&#xff09;一、题目内容题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示二、思路分析三、代码一、题目内容 题目描述 某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构&#xff…

Nacos配置拉取及配置动态刷新原理【源码阅读】

Nacos配置拉取及配置刷新原理 一、初始化时获取配置文件 背景 SpringCloud项目中SpringBoot在启动阶段除了会创建SpringBoot容器&#xff0c;还会通过bootstrap.yml构建一个SpringCloud容器&#xff0c;之后会在准备上下文阶段通过SPI加载实现类后&#xff0c;会进行配置合并…

Linux(传输层二)

文章目录0. 前言1. TCP协议1-1 TCP协议段格式1. TCP如何解包&#xff1f;2. TCP协议如何交付&#xff08;应用层- - 客户&#xff09;&#xff1f;3. 如何理解报文本身&#xff1f;4. 如何理解报文字段&#xff1f;1-2 确认应答(ACK)机制1-3 超时重传机制1-4 连接管理机制1. TC…

Kafka中那些巧妙的设计

一、kafka的架构 Kafka是一个分布式、多分区、基于发布/订阅模式的消息队列&#xff08;Message Queue&#xff09;&#xff0c;具有可扩展和高吞吐率的特点。 kafka中大致包含以下部分&#xff1a; Producer&#xff1a; 消息生产者&#xff0c;向 Kafka Broker 发消息的客户…