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

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

工厂模式

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

核心:

  • 实例化对象不使用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.mfbz.cn/a/788750.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业应对策略:全面防御.DevicData-P-xxxxxx勒索病毒

引言 在数字化时代,网络安全已成为不可忽视的重要议题。随着互联网的普及,各种网络威胁层出不穷,其中勒索病毒以其独特的攻击方式和巨大的破坏性,给个人用户和企业带来了严重的经济损失和数据安全风险。在众多勒索病毒中&#xff…

前端javascript中的排序算法之选择排序

选择排序(Selection Sort)基本思想: 是一种原址排序法; 将数组分为两个区间:左侧为已排序区间,右侧为未排序区间。每趟从未排序区间中选择一个值最小的元素,放到已排序区间的末尾,从…

LeetCode加油站(贪心算法/暴力,分析其时间和空间复杂度)

题目描述 一.原本暴力算法 最初的想法是:先比较gas数组和cost数组的大小,找到可以作为起始点的站点(因为如果你起始点的油还不能到达下一个站点,就不能作为起始点)。当找到过后,再去依次顺序跑一圈,如果剩余的油为负数…

11、Python之变量:看得见还是看不见

引言 在前面一篇关于Python变量的文章中,更多地结合对象的内存结构及字节码指令,来看不同代码针对不同的类型的对象的不同效果。 今天这篇文章中,想对新手在使用Python变量中,可能遇到的其他困惑,再展开来说一下。 大…

乐器培训课程报名小程序模板源码

模板介绍 一款实用的音乐课程,乐器培训,艺术类网页课程报名手机小程序模板下载。包含:主页、列表、个人中心、报名等模块。 图片演示 乐器培训课程报名小程序模板源码

《Windows API每日一练》9.13资源-鼠标位图和字符串

鼠标指针位图(Mouse Cursor Bitmap)是用于表示鼠标指针外观的图像。在 Windows 窗口编程中,可以使用自定义的鼠标指针位图来改变鼠标的外观,并提供更加个性化的用户体验。 ■以下是一些与鼠标指针位图相关的要点: ●…

九、C++11常用新特性—模板的优化

1.模板的右尖括号 在泛型编程种,模板实例化有一个非常繁琐的地方,那就是连续的两个右尖括号(>>)会被编译器解析成右移操作,而不是模板参数表的结束,在C11以前需要在>>之间加上一个空格> >。C11之后…

中职网络安全Server2216

任务环境说明:✓ 服务器场景:Server2216(开放链接)✓ 用户名:root密码:1234561.黑客通过网络攻入本地服务器,通过特殊手段在系统中建立了多个异常进程找出启动异常进程的脚本,并将其绝对路径作为Flag值提交…

WindowsMac共享文件夹设置

共享文件夹设置 共享文件夹设置Windows系统设置步骤一:设置共享文件夹步骤二: 访问共享文件夹 Mac系统中设置共享文件夹步骤一:设置共享文件夹步骤二:访问共享文件夹 小贴士结论 共享文件夹设置 有时需要在多台电脑之间共享文件夹&#xff0…

学习嵌入式对于学历有要求吗?

学习嵌入式系统开发通常并不对学历有严格的要求,尤其是在技术行业中,实际的技能和经验往往比学历更为重要。我收集归类了一份嵌入式学习包,对于新手而言简直不要太棒,里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕…

【C++报错已解决】Multiple Definition of Symbol

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 引言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法:方法一:使用extern关键…

设计模式之Facade设计模式

Facade设计模式,也称为外观模式,是一种结构型设计模式,它主要用于为子系统中的一组接口提供一个统一的高层接口,从而使得子系统更加容易使用。以下是关于Facade设计模式的详细介绍: 一、定义 Facade模式为多个复杂的…

【单片机毕业设计选题24054】-基于STM32的水质检测系统

系统功能: 主要功能模块原理图: 电源时钟烧录接口: 单片机和按键输入电路: 传感器采集电路: 资料获取地址 系统主要功能模块代码 初始化代码: /* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration-----------------------------------------------…

Golang | Leetcode Golang题解之第226题翻转二叉树

题目: 题解: func invertTree(root *TreeNode) *TreeNode {if root nil {return nil}left : invertTree(root.Left)right : invertTree(root.Right)root.Left rightroot.Right leftreturn root }

C++ | Leetcode C++题解之第225题用队列实现栈

题目&#xff1a; 题解&#xff1a; class MyStack { public:queue<int> q;/** Initialize your data structure here. */MyStack() {}/** Push element x onto stack. */void push(int x) {int n q.size();q.push(x);for (int i 0; i < n; i) {q.push(q.front());…

操作系统:信号究竟是什么?如何产生?

OS信号 一、信号的概念二、信号的产生1&#xff09;终端按键产生信号1、 前台进程、后台进程2、验证终端按键是否产生信号 2&#xff09;调用系统函数向进程发信号3&#xff09;硬件异常产生信号1、浮点数溢出&#xff0c;CPU产生信号2 浮点数溢出&#xff0c;产生信号原理3. 空…

字节码编程javassist之修改返回值

写在前面 本文看下如何修改返回值。 代码 需要增强的类&#xff1a; package com.dahuyou.javassist.huohuo.cc;import java.math.BigDecimal;public class MyApiTestNoAnnotation {public double queryUserInfo(String uId){return BigDecimal.ONE.doubleValue();}}插桩类…

JavaWeb—js(3)

Bom dom: document object model(文档对象模型), 是处理html、xml的标准编写接口。 节点和元素 整个页面也就是整个文档我们称之为文档节点; 文档节点使用document来表示; 页面中的所有标签我们称之为元素&#xff0c;使用element来表示; 如此处的文本、属性、注释等&…

腾讯又一平台即将停止运营

随着腾讯公司业务和战略的调整&#xff0c;某些业务逐渐退出历史舞台&#xff0c;如“腾讯直播平台NOW”&#xff0c;以及“QQ签到”&#xff0c;“腾讯待办”&#xff0c;“企鹅FM音频平台”等&#xff0c;最近又有一则重磅消息&#xff0c;那就是“腾讯课堂”也即将停止运营。…

前端构建工具(webpackvite)

这里写目录标题 构建工具webpack介绍配置文件简介entryoutputloaderbabel插件开发服务器&#xff08;webpack-dev-server&#xff09;soureMap vite 构建工具 当我们习惯了在node中编写代码的方式后&#xff0c;在回到前端编写html、css、js这些东西会感觉到各种的不便。比如:…