设计模式之工厂模式(简单工厂、工厂方法、抽象工厂)

news2024/9/23 21:23:10

写在前面:本文是个人在学习设计模式时的所思所想,汇总了其他博主及自己的感悟思考,可能存在出入,请大家理性食用~~

工厂模式

在工厂模式中,父类决定实例的生成方式,但并不决定所要生成的具体的类具体的处理全部交给子类负责。这样就可以将生成实例的框架和实际负责生成实例的类解耦。

核心:

  • 实例化对象不使用new,用工厂方法创建对象。
  • 使用工厂统一管理对象的创建,将调用者跟实现类解耦。

1.1. 简单工厂模式

简单工厂模式又叫静态工厂方法模式(因为工厂类定义了一个静态方法)

简单工厂模式的角色包括三个

  • 抽象产品角色
  • 具体产品角色
  • 工厂类角色

  • 抽象产品角色:
public interface Weapon{
    //所有的武器都有攻击行为
    public void attack();
}
  • 具体产品角色:
//坦克(具体产品角色)
public class Tank implements Weapon{
    @Override
    public void attack() {
        System.out.println("坦克开炮!");
    }
}
// 战斗机(具体产品角色)
public class Fighter implements Weapon{
    @Override
    public void attack() {
        System.out.println("战斗机投下原子弹!");
    }
}
//匕首(具体产品角色)
public class Dagger implements 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().length() == 0) {
            return null;
        }
        Weapon weapon = null;
        if ("TANK".equals(weaponType)) {
            weapon = new Tank();
        } else if ("FIGHTER".equals(weaponType)) {
            weapon = new Fighter();
        } else if ("DAGGER".equals(weaponType)) {
            weapon = new Dagger();
        } else {
            throw new RuntimeException("不支持该武器!");
        }
        return weapon;
    }
}
  • 测试类:
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开闭原则,在进行系统拓展时,需要修改工厂类。

1.2. 工厂方法模式

工厂方法模式既保留了简单工厂的优点,同时又解决了简单工厂的缺点。

工厂方法模式的角色包括四个

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

  • 抽象产品角色:
//武器类(抽象产品角色)
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 weapon = factory.get();
        weapon.attack();

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

如果想扩展一个新的产品,只要新增一个产品类,再新增一个该产品对应的工厂即可,例如新增:匕首

public class Dagger extends Weapon{
    @Override
    public void attack() {
        System.out.println("砍丫的!");
    }
}
public class DaggerFactory implements WeaponFactory{
    @Override
    public Weapon get() {
        return new Dagger();
    }
}
  • 客户端程序:
public class Client {
    public static void main(String[] args) {
        //实例化不同的工厂
        WeaponFactory factory = new GunFactory();
        Weapon weapon = factory.get();
        weapon.attack();

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

        WeaponFactory factory2 = new DaggerFactory();
        Weapon weapon2 = factory2.get();
        weapon2.attack();
    }
}

因此可以看出在进行功能拓展时,不需要修改之前的源码,显然工厂方法模式更符合OCP原则。

优点

    • 拓展性高,如果想增加一个产品,只需新增一个产品类及其对应的工厂类即可。
    • 弱化抽象工厂的职责,将具体产品的实现交给其他工厂,职责分工明确。

缺点

    • 每次再新增一个产品时,都需要增加一个具体类及其对应的工厂类,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

在Spring框架中,BeanFactory使用的是工厂方法模式

源码位置:

抽象工厂角色Bean Factory:

实现BeanFatory的具体工厂:

实现BeanFatory的具体工厂角色:

1.3. 抽象工厂模式

抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。

抽象工厂方法模式的角色也包括四个

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

类图:

其他实现原理和流程同工厂方法模式。只不过抽象工厂中包含很多个具体的功能,是一个超级工厂父类。

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

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

相关文章

带你了解“Java新特性——模块化”

Java平台从Java 8向Java 9及更高版本的进化,其中引入了一个重要的新特性——模块系统(Project Jigsaw)。模块系统的目的是解决大型应用的依赖管理问题,提升性能,简化JRE,增强兼容性和安全性,并提…

求整数数组的子集【C语言】

方法1:通过二进制位,因为n个整数数组的子集有2的n次方个,例如整数数组为{1,2,3},子集有2的3次方,8个; 期望的输出形式 其中需要了解关注的是 n&1判断最低位是否有数。如果一个子集为{2},利用二进制位…

C++初阶:类与对象(一)

✨✨所属专栏:C✨✨ ✨✨作者主页:嶔某✨✨ 类的定义 定义格式 • class为定义类的关键字,后面跟类的名字,{}中为类的主体,注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员;类中的变量称为类的…

2024最新PyCharm下载安装

(1)打开官网:https://www.jetbrains.com/ (2)点击pycharm (3)进入后点击下载按钮 (4)此时有两个选择:有专业版和社区版 PyCharm有专业版(Prof…

zynq启动和程序固化流程

普通FPGA启动 FPGA的启动方式主要包含主动模式、被动模式和JTAG模式。 主动模式(AS模式) 当FPGA器件上电时,它作为控制器从配置器件EPCS中主动发出读取数据信号,并将EPCS的数据读入到自身中,实现对FPGA的编程。这种…

公众号运营秘籍:8 大策略让你的粉丝翻倍!

在当今信息爆炸的时代,微信公众号的运营者们面临着前所未有的挑战:如何在这个充满竞争的红海中脱颖而出,吸引并留住粉丝?事实上,微信公众号的红利期并未完全过去,关键在于我们如何策略性地运营,…

关于复现StableDiffusion相关项目时踩坑的记录

研究文生图也有了一段时间,复现的论文也算是不少,这篇博客主要记录我自己踩的坑。 目前实现文生图的项目主要分为两类: 一、基于Stable-diffusion原项目文件实现 原项目地址:https://github.com/Stability-AI/stablediffusion …

【自监督学习】DINO in ICCV 2021

一、引言 论文: DINO: Emerging Properties in Self-Supervised Vision Transformers 作者: Facebook AI Research 代码: DINO 特点: 对于一张图片,该方法首先进行全局和局部的裁剪与增强并分别送入教师和学生网络&am…

YOLOv10改进 | 图像去雾 | MB-TaylorFormer改善YOLOv10高分辨率和图像去雾检测(ICCV,全网独家首发)

一、本文介绍 本文给大家带来的改进机制是图像去雾MB-TaylorFormer,其发布于2023年的国际计算机视觉会议(ICCV)上,可以算是一遍比较权威的图像去雾网络, MB-TaylorFormer是一种为图像去雾设计的多分支高效Transformer…

WordPress PHP Everywhere <= 2.0.3 远程代码执行漏洞(CVE-2022-24663)

前言 CVE-2022-24663 是一个影响 WordPress 插件 PHP Everywhere 的远程代码执行(RCE)漏洞。PHP Everywhere 插件允许管理员在页面、文章、侧边栏或任何 Gutenberg 块中插入 PHP 代码,以显示基于评估的 PHP 表达式的动态内容。然而&#xff…

FreeCAD: 将STL格式文件转换为step格式文件的记录

首先我们需要下载开源的FreeCAD软件,官网链接如下: FreeCAD: Your own 3D parametric modeler 傻瓜式安装,跳过~ FreeCAD 是一款免费的开源CAD软件,支持多种文件格式转换,包括STL到STEP。 步骤: 打开Free…

PTrade常见问题系列7

获取可转债数据为空。 量化交易内,获取可转债标的行情,提示报错12319*.SZ不支持。 1、建议客户在研究内执行get_price,返回无数据; 2、怀疑asset.pk内不存在该可转债代码,再研究内执行import pandas as pd df pd.re…

前端使用pinia中存入的值

导入pinia,创建pinia实例 使用pinia中的值

Rust: 高性能序列化库Fury PK bincode

在序列化库中,传统的有Json,XML,性能好的有thrift,protobuf等。 对于二进制库来讲,据Fury官网的介绍,Fury性能要远远好于protobuf,且不象protobuf还需要定义IDL(即写.proto文件),非常轻便&#…

数据库-ubuntu环境下安装配置mysql

文章目录 什么是数据库?一、ubuntu环境下安装mysql二、配置mysql配置文件1.先登上root账号2.配置文件的修改show engines \G; mysql和mysqld数据库的基础操作登录mysql创建数据库显示当前数据库使用数据库创建表插入students表数据打印students表数据select * from …

【ArcGIS 小技巧】为国空用地字段设置属性域,快速填充属性值并减少出错

属性域属性是描述字段类型可用值的规则。可用于约束表或要素类的任意特定属性中的允许值。——ArcGIS Pro 帮助文档 简单理解属性域:对于一个含义为性别的字段,我们一般会给的属性值有男、女两种。我们可以将这两种属性值制作成属性域并指定给该字段&…

05STM32EXIT外部中断中断系统

STM32EXIT外部中断&中断系统 中断系统中断触发条件:中断处理流程和用途: STM32中断NVIC嵌套中断向量控制器基本结构 中断系统 中断触发条件: 对外部中断来说,可以是引脚发生了电平跳变 对定时器来说,可以是定时的…

nginx初理解

没有ngix时,有两台服务器,供访问 1. 现在有两台服务器上同样的路径下都放了一个, 都能通过ip加端口访问到页面 后端项目 (查看tomcat中的配置中的 server.xml,能找到项目路径) tomacat 也都有 两个…

【人工智能】Transformers之Pipeline(概述):30w+大模型极简应用

​​​​​​​ 目录 一、引言 二、pipeline库 2.1 概述 2.2 使用task实例化pipeline对象 2.2.1 基于task实例化“自动语音识别” 2.2.2 task列表 2.2.3 task默认模型 2.3 使用model实例化pipeline对象 2.3.1 基于model实例化“自动语音识别” 2.3.2 查看model与task…

Vue2 基础十Vuex

代码下载 Vuex 概述 组件之间共享数据的方式: 父组件向子组件传值,是以属性的形式绑定值到子组件(v-bind),然后子组件用属性props接收。子组件向父组件传值,子组件用 $emit() 自定义事件,父组…