03_Spring_Bean专题

news2024/11/22 0:35:01

在说Bean之前,我们先对工厂模式有个简单的认识,把这一部分的知识做一个铺垫。后面我们说到Spring Bean的管理会用来到这个模式。

一、工厂模式

工厂模式是一种设计模式,那设计模式又是什么呢?

简单来说,设计模式,它是一种可以被重复利用的解决方案。1995年《设计模式》由由Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides合著,这四位作者被称为“四人组”(GoF,Gang of Four)。

在书中描述了23种设计模式,因为“四人组”当时出书时间比较早,如果到现在来说应该还会有一些书中没有纳入的新的设计模式。当我们平时说的设计模式就是指的这23种设计模式了。

GoF23种设计模式又可以分为三大类:

1、解决对象创建问题的(创建型),有5个

单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式

2、一些数或者是对象组装在一起的经典结构(结构型),有7个

代理模式、装饰模式、适配器模式、组合模式、享元模式、外观模式、桥接模式

3、解类或者是对象之前交互问题(行为型)

策略模式、模式方法模式、观察者模式、责任链模式、迭代子模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

现在我们要说的是工厂模式,它是用来解决创建问题的,我们的Bean产生不就是要重点解决谁帮我们创建对象,谁帮我们维护各个对象之间的关系吗?所以Spring底层使用了大量的工厂模式。

工厂模式的三种形态

  • 简单工厂模式:它不属于23种设计模式之一。简单工厂模式又叫静态工厂方法模式,它是工厂方法模式的一种特殊实现
  • 工厂方法模式
  • 抽象工厂模式

接下来我们对这三种形态做进一步的了解

简单工厂模式

对于简单工厂模式来说,它分为三个角色:抽象产品角色、具体产品角色、工厂类角色

下面我们用实际的代码来说明

抽象产品角色,它是对具体的各个产品的行为特征的抽象,它是不能产生具体的对象(或者说产品的)

/**
 * 抽象产品角色
 */
public abstract class Weapon {

    /**
     * 所有武器都有攻击的行为
     */
    public abstract void attack();
}

具体产品角色,它就是实实在在在描最终要生产的对象/产品,一般来说具体产品角色是会有多个的,下面有三个类,它们都是具象化的具体产品描述。

/**
 * 具体产品角色
 */
public class Tank extends Weapon {
    @Override
    public void attack() {
        System.out.println("坦克开炮~");
    }
}


/**
 * 具体产品角色
 */
public class Fighter extends Weapon {
    @Override
    public void attack() {
        System.out.println("战斗机投下导弹~");
    }
}


/**
 * 具体产品角色
 */
public class Dagger extends Weapon {
    @Override
    public void attack() {
        System.out.println("匕首攻击~");
    }
}

工厂类角色,这个角色就是具体来为我们提供对象的,工厂嘛肯定是生产产品的地方

/**
 * 工厂类角色
 */
public class WeaponFactory {
    /**
     * 根据不同的武器类型,返回不同的武器对象
     * @param weaponType
     * @return
     */
    public static Weapon get(String weaponType) {
        if (weaponType == null || weaponType.trim().isEmpty()) {
            throw new RuntimeException("要生产生什么武器,请先告诉我~~");
        }
        Weapon weapon = switch (weaponType) {
            case "TANK" -> new Tank();
            case "FIGHTER" -> new Fighter();
            case "DAGGER" -> new Dagger();
            default -> throw new RuntimeException("不支持生产该武器~~");
        };
        return weapon;
    }
}

当我们要使用具体产品/对象的时候,我们不直接new了(对象是怎么生产出来的,怎和new的,有没有一些复杂的逻辑都不管了),而是让这个工厂帮我们去生产,我们只需要告诉它我们的需求即可。如下所示的客户端代码

public class Client {
    public static void main(String[] args) {
        Weapon weapon1 = WeaponFactory.get("TANK");
        weapon1.attack();

        Weapon weapon2 = WeaponFactory.get("FIGHTER");
        weapon2.attack();

        Weapon weapon3 = WeaponFactory.get("DAGGER");
        weapon3.attack();
    }
}

上面这种就是简单工厂模式,这种模式的优缺点如下:

优点:客户端不再关心产品创建的所有细节工作,需要哪个对象直接向工厂提需求即可。这样做到了职责分离。

缺点:对于某一个类型下的所有产品都是由工厂生产的,万一这个工厂类出点问题,怎么办?万一后面系统要扩展了,我们不得倒过去修改工厂类,这不符合OCP开闭原则啊!

工厂方法模式

工厂方法模式是对简单工厂模式的一种优化,它在工厂角色上再多了一个抽象工厂角色,所以它的角色分为如下一些:

抽象工厂角色、具体工厂角色、抽象产品角色、具体产品角色

我们通过代码来看一看

抽象产品

/**
 * 抽象产品角色
 */
public abstract class Weapon {
    public abstract void attack();
}

具体产品

/**
 * 具体产品角色
 */
public class Gun extends Weapon {
    @Override
    public void attack() {
        System.out.println("开枪射击~~");
    }
}

/**
 * 具体产品角色
 */
public class Fighter extends Weapon {
    @Override
    public void attack() {
        System.out.println("战斗机攻击~~");
    }
}

抽象工厂角色

/**
 * 抽象工厂角色
 */
public interface WeaponFactory {
    Weapon get();
}

具体工厂角色

/**
 * 具体工厂角色
 */
public class GunFactory implements WeaponFactory {
    @Override
    public Weapon get() {
        return new Gun();
    }
}

/**
 * 具体工厂角色
 */
public class FighterFactory implements WeaponFactory {
    @Override
    public Weapon get() {
        return new Fighter();
    }
}

最终客户端需要哪个产品直接找对应的工厂索要即可

public class Client {
    public static void main(String[] args) {
        WeaponFactory factory = new GunFactory();
        Weapon gun = factory.get();
        gun.attack();

        WeaponFactory factory1 = new FighterFactory();
        Weapon fighter = factory1.get();
        fighter.attack();
    }
}

这个时候我们可以看到当我们想要扩展一个新的产品时,不会动到现有结构,我们只需要新增一个具体产品类,同时再新增一个对应的具体工厂即可。

工厂方法模式的又有哪些优缺点呢?

优点:扩展性高

缺点:每增加一个产口就需要增加一个具体类的对象实现工厂,类的数量增长过快,在一定程度上增加了系统的复杂度。

抽象工厂模式

抽象工厂模式相对于工厂方法模式做了一个折中的处理,工厂方法模式是一个产品对一个工厂类,而抽象工厂模式是多个产品对应一个工厂类。

抽象工厂模式会把产品进行分类,每一类产生提供一个具体的生产工厂

抽象工厂模工中有如下四个角色

抽象工厂角色、具体工厂角色、抽象产品角色、具体产品角色

抽象产品

/**
 * 抽象产品族 - 武器
 */
public abstract class Weapon {
    public abstract void attack();
}


/**
 * 抽象产品族 - 水果
 */
public abstract class Fruit {
    /**
     * 水果的甜度
     */
    public abstract void sweetness();
}

具体产品

/**
 * 武器产品 - Gun
 */
public class Gun extends Weapon {
    @Override
    public void attack() {
        System.out.println("开枪射击~~");
    }
}

/**
 * 武器产品 - Dagger
 */
public class Dagger extends Weapon {
    @Override
    public void attack() {
        System.out.println("匕首砍~~~");
    }
}


/**
* 水果产品 - Grape
*/
public class Grape extends Fruit {
    @Override
    public void sweetness() {
        System.out.println("草莓甜度 - 高");
    }
}


/**
* 水果产品 - Blueberry
*/
public class Blueberry extends Fruit {
    @Override
    public void sweetness() {
        System.out.println("葡萄甜度 - 中");
    }
}

抽象工厂

/**
 * 抽象工厂类
 */
public abstract class AbstractFactory {
    public abstract Fruit getFruit(String fruitType);
    public abstract Weapon getWeapon(String weaponType);
}

具体工厂

/**
 * 具体工厂类 - 武器
 */
public class WeaponFactory extends AbstractFactory {
    @Override
    public Fruit getFruit(String fruitType) {
        return null;
    }

    @Override
    public Weapon getWeapon(String weaponType) {
        if(weaponType == null || weaponType.isEmpty()) {
            throw new RuntimeException("请提供具体要生产的武器~~");
        }
        return switch(weaponType) {
            case "Gun" -> new Gun();
            case "Dagger" -> new Dagger();
            default -> throw new RuntimeException("无法产生该武器~~");
        };
    }
}


/**
 * 具体工厂类 - 水果
 */
public class FruitFactory extends AbstractFactory {
    @Override
    public Fruit getFruit(String fruitType) {
        if(fruitType == null || fruitType.isEmpty()) {
            throw new RuntimeException("请提供具体要生产的水果~~");
        }
        return switch(fruitType){
            case "grape" -> new Grape();
            case "blueberry" -> new Blueberry();
            default -> throw new RuntimeException("不支持的水果类型");
        };
    }

    @Override
    public Weapon getWeapon(String weaponType) {
        return null;
    }
}

客户端在使用时可以如下:

// 测试程序
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory = new FruitFactory();
        Fruit blueberry = factory.getFruit("blueberry");
        blueberry.sweetness();
        Fruit grape = factory.getFruit("grape");
        grape.sweetness();
        System.out.println("=======================================");
        factory = new WeaponFactory();

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

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

相关文章

三十一、构建完善微服务——API 网关

一、API 网关基础 系统拆分为微服务后,内部的微服务之间是互联互通的,相互之间的访问都是点对点的。如果外部系统想调用系统的某个功能,也采取点对点的方式,则外部系统会非常“头大”。因为在外部系统看来,它不需要也没…

深入理解 Redis跳跃表 Skip List 原理|图解查询、插入

1. 简介 跳跃表 ( skip list ) 是一种有序数据结构,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。 在 Redis 中,跳跃表是有序集合键的底层实现之一,那么这篇文章我们就来讲讲跳跃表的实现原理。 2. …

MediaSession学习总结

1.框架预览 2.用法 2.1参考链接: MediaSession 简单使用 2.2 服务端要实现MediaBrowserService; 主要实现的功能: mPlaybackState new PlaybackStateCompat.Builder().setState(PlaybackStateCompat.STATE_NONE, currentPostion, 1.0f).…

学习大数据DAY61 宽表加工

目录 模型设计 加工宽表 任务调度: 大表 - 把很多数据整合起来 方便后续的明细查询和指标计算 模型设计 设计 建模 设计: excel 文档去编写 建模: 使用建模工具 PowerDesigner Navicat 在线画图工具... 把表结构给绘 制出来 共享\项目课工具\pd 加工宽表 数…

零基础入门Flink,掌握基本使用方法

Flink基本概念 首先来讲,Flink是一个面向数据流处理和批处理的分布式开源计算框架。 那么,流处理和批处理分别处理什么样的数据呢,这就涉及两个概念-无界流和有界流 无界流VS有界流 任何类型的数据都可以形成流数据,比如用户…

Linux设置以及软件的安装(hadoop集群安装02)

一、Linux的常见设置 1、设置静态IP vi /etc/sysconfig/network-scripts/ifcfg-ens33 如何查看自己的虚拟机的网关: 完整的配置(不要拷贝我的): TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no&…

数据中台方法论:数据汇聚

文章目录 一、数据汇聚概述二、 汇聚数据类型2.1 结构化数据2.2 半结构化数据2.3 非结构化数据 三、汇聚数据模式四、汇聚数据方法四、数据汇聚工具五、数据汇聚使用经验 数据小伙伴们,之前咱们长篇大论的聊聊过【数据中台建设方法论从0到1】,从数据中台…

【Maven】nexus 配置私有仓库配置【转】

介绍:【Maven】Nexus几个仓库的介绍-CSDN博客 一、仓库类型 proxy 远程仓库的代理,比如说nexus配置了一个central repository的proxy,当用户向这个proxy请求一个artifact的时候,会现在本地查找,如果找不到,则会从远程…

3C产品说明书电子化转变:用户体验、环保与商业机遇的共赢

在科技日新月异的当代社会,3C产品(涵盖计算机类、通信类和消费类电子产品)已成为我们日常生活中不可或缺的重要元素。与此同时,这些产品的配套说明书也经历了一场从纸质到电子化的深刻变革。这一转变不仅体现了技术的飞速进步&…

【YOLOv8】安卓端部署-2-项目实战

文章目录 1 准备Android项目文件1.1 解压文件1.2 放置ncnn模型文件1.3 放置ncnn和opencv的android文件1.4 修改CMakeLists.txt文件 2 手机连接电脑并编译软件2.1 编译软件2.2 更新配置及布局2.3 编译2.4 连接手机 3 自己数据集训练模型的部署4 参考 1 准备Android项目文件 1.1…

虚拟网卡驱动和DM9000C移植

网卡驱动程序框架 网卡驱动程序“收发功能”: 只要把上层的数据发给网卡,从网卡来的数据构造成包给上层即可。网卡只需要 “socket”编程,不需要打开某设备。 驱动程序都是以面向对象的思想写的,都有相关的结构体。 编程步骤 …

Vue3 + Vite 项目引入 Typescript

文章目录 一、TypeScript简介二、TypeScript 开发环境搭建三、编译方式1. 自动编译单个文件2. 自动编译整个项目 四、配置文件1. compilerOptions基本选项严格模式相关选项(启用 strict 后自动包含这些)模块与导入相关选项 2. include 和 excludeinclude…

Cyberchef使用功能之-多种压缩/解压缩操作对比

cyberchef的compression操作大类中有大量的压缩和解压缩操作,每种操作的功能和区别是什么,本章将进行讲解,作为我的专栏《Cyberchef 从入门到精通教程》中的一篇,详见这里。 关于文件格式和压缩算法的理论部分在之前的文章《压缩…

Istio分布式链路监控搭建:Jaeger与Zipkin

分布式追踪定义 分布式追踪是一种用来跟踪分布式系统中请求的方法,它可以帮助用户更好地理解、控制和优化分布式系统。分布式追踪中用到了两个概念:TraceID 和 SpanID。 TraceID 是一个全局唯一的 ID,用来标识一个请求的追踪信息。一个请求…

Linux修改/etc/hosts不起作用(ping: xxx: Name or service not known)的解决方法——开启NSCD

​ 问题描述 起因是我在实验室云资源池的一台虚拟机(CentOS 8.5)上的/etc/hosts文件中为Fabric网络节点的域名指定了IP: IP可以ping通,但是ping域名时提示ping: xxx: Name or service not known。 问题本身应该是Linux通用的&a…

Python中Tushare(金融数据库)入门详解

文章目录 Python中Tushare(金融数据库)入门详解一、引言二、安装与注册1、安装Tushare2、注册与获取Token 三、Tushare基本使用1、设置Token2、获取数据2.1、获取股票基础信息2.2、获取交易日历2.3、获取A股日线行情2.4、获取沪股通和深股通成份股2.5、获…

【网络】网络抓包与协议分析

网络抓包与协议分析 一. 以太网帧格式分析 这是以太网数据帧的基本格式,包含目的地址(6 Byte)、源地址(6 Byte)、类型(2 Byte)、数据(46~1500 Byte)、FCS(4 Byte)。 Mac 地址类型 分为单播地址、组播地址、广播地址。 单播地址:是指第一个字节的最低位…

RabbitMQ的工作队列在Spring Boot中实现(详解常⽤的⼯作模式)

上文着重介绍RabbitMQ 七种工作模式介绍RabbitMQ 七种工作模式介绍_rabbitmq 工作模式-CSDN博客 本篇讲解如何在Spring环境下进⾏RabbitMQ的开发.(只演⽰部分常⽤的⼯作模式) 目录 引⼊依赖 一.工作队列模式 二.Publish/Subscribe(发布订阅模式) …

python学习_3.正则表达式

来源:B站/麦叔编程 1. 正则表达式的7个境界 假设有一段文字: text 身高:178,体重:168,学号:123456,密码:9527要确定文本中是否包含数字123456,我们可以用in运算符,也可以使用inde…

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

数据容器-----元组 定义格式,特点,相关操作 元组一旦定义,就无法修改 元组内只有一个数据,后面必须加逗号 """ #元组 (1,"hello",True) #定义元组 t1 (1,"hello") t2 () t3 tuple() prin…