设计模式之工厂模式,但是宝可梦

前言

工作一年了,业务代码写太多,还是得自驱提升点技术。希望工作一年后写出来的能有更多自己的思考。

正文

工厂模式是一种创建型设计模式,主要的目的还是在创建一个对象时提供更灵活、更易扩展的机制。

简单工厂模式

情景模拟

小智到商店去买精灵球,精灵球的种类繁多。商店店员会在库房中根据小智的要求拿对应的精灵球。在这个过程中,作为买家,小智不需要关注精灵球放在库房的哪一个位置。

/**
* 精灵球可以查看成功率,实现类有普通球和超级球
**/
public interface Ball {void showDetails();
}class NormalBall implements Ball{@Overridepublic void showDetails() {System.out.println("This is a normal ball. 15% to catch");}
}class SuperBall implements Ball{@Overridepublic void showDetails() {System.out.println("This is a super ball. 25% to catch");}
}/*** 精灵球商店*/
public class BallShop {public static Ball getBall(int ballCode){if (ballCode == 0){// 去放普通球的地方...return new NormalBall();}if (ballCode == 1){// 去放超级球的地方...return new SuperBall();}return null;}
}

对比一下直接new创建类和用工厂模式创建类:

	Ball ball1 = new NormalBall();Ball ball2 = new SuperBall();Ball normalBall = BallShop.getBall(0);Ball superBall = BallShop.getBall(1);

有一个很直观的区别:我根本不需要关心new的是什么实现类,我只需要传入对应的参数,告诉工厂我需要什么实现类。更规范一点,可以把0,1等数替换为枚举类,这样作为调用方,我无需关注怎么new的,new的什么类,我只需要相信工厂类会返回给我想要的类。

举例

DateFormat是简单工厂模式的经典运用,获取实例对象时,我只需要在getTimeInstance()方法传入类提供的枚举类,我无需关注内部实现细节,传入不同参数,后续的具体实现也就不同。

		DateFormat timeInstance = DateFormat.getTimeInstance(DateFormat.FULL);String format1 = timeInstance.format(new Date());DateFormat timeInstance2 = DateFormat.getTimeInstance(DateFormat.DATE_FIELD);String format2 = timeInstance2.format(new Date());System.out.println(format1);  // 中国标准时间 上午12:37:33System.out.println(format2);  // 上午12:37

不足

简单工厂模式对于简单场景是很友好的,实现很简单,如果能确保业务不再扩展,简单工厂模式是很好的选择。然而如果业务有扩展,简单工厂模式的弊端就体现出来了。

如果现在我新增了一个新的球种类——大师球。现在商店里的店员都需要知道大师球放在哪个位置,加重了商店店员的逻辑(工厂内创建逻辑)

class MasterBall implements Ball{@Overridepublic void showDetails() {System.out.println("MasterBall!!. 100% to catch");}
}

对应的工厂类就要做相应的适配:

public class BallShop {public static Ball getBall(int ballCode){if (ballCode == 0){// 去放普通球的地方...return new NormalBall();}if (ballCode == 1){// 去放超级球的地方...return new SuperBall();}if (ballCode == 2){// 去放大师球的地方...return new MasterBall();}return null;}
}

新增一个if分支的同时打破了开闭原则(对扩展开放,对修改封闭),其次,工厂类涵盖了所有的创建逻辑,高内聚。
为了解决业务会有新增的情况,根据面向对象编程的原则,抽象!引入工厂方法模式

工厂方法模式

场景模拟

由于精灵球的种类不断增多,店员没办法记住每种球的位置(内聚太多逻辑),所以精灵球商店把店面分成了几个区域,每个区域售卖一种球,一个店员负责一个区域,这个店员只需要关注这个区域售卖的球在哪里。作为买家小智,他只需要知道他想买哪种球,然后去对应的分区,他仍然不需要关心球在哪里存放。

于是工厂类修改为:

public interface BallShopNew {Ball findBall();
}class NormalBallFactory implements BallShopNew{@Overridepublic Ball findBall() {return new NormalBall();}
}class SuperBallFactory implements BallShopNew{@Overridepublic Ball findBall() {return new SuperBall();}
}class MasterBallFactory implements BallShopNew{@Overridepublic Ball findBall() {return new MasterBall();}
}

使用方式:

public class FactoryDemo {public static void main(String[] args) {Ball masterBall = new MasterBallFactory().findBall();Ball normalBall = new NormalBallFactory().findBall();masterBall.showDetails();normalBall.showDetails();}
}

现在如果新推出了一种新的球,只需要开辟新的分区,聘请一个新店员(创建新的实现类),遵循了开闭原则。

不足

如果这个时候,产品维度发生了扩展,商店不止卖球了,还要卖贴纸。当产品变成复数,每个工厂就要进行相应的修改来支持新的产品,或者新增对应数量的新的工厂和实现类。系统中的类会变得极其多。抽象工厂模式用于解决复数产品的场景。

抽象工厂模式

抽象工厂模式首先将产品抽象:

public interface Label {void showColor();
}class NormalLabel implements Label{@Overridepublic void showColor() {System.out.println("红白配色");}
}class MasterLabel implements Label{@Overridepublic void showColor() {System.out.println("紫色配色");}
}

再在抽象工厂中引入抽象产品。

public interface BallLabelShop {Ball findBall();Label findLabel();
}class NormalBallLabelShop implements BallLabelShop{@Overridepublic Ball findBall() {return new NormalBall();}@Overridepublic Label findLabel() {return new NormalLabel();}
}class MasterBallLabelShop implements BallLabelShop{@Overridepublic Ball findBall() {return new MasterBall();}@Overridepublic Label findLabel() {return new MasterLabel();}
}

使用:

public class FactoryDemo {public static void main(String[] args) {MasterBallLabelShop masterBallLabelShop = new MasterBallLabelShop();Ball ball = masterBallLabelShop.findBall();Label label = masterBallLabelShop.findLabel();ball.showDetails();label.showColor();NormalBallLabelShop normalBallLabelShop = new NormalBallLabelShop();Ball ball2 = normalBallLabelShop.findBall();Label label2 = normalBallLabelShop.findLabel();ball2.showDetails();label2.showColor();}
}/**
MasterBall!!. 100% to catch
紫色配色
This is a normal ball. 15% to catch
红白配色
**/

这里可能就有读者会问,这不是和工厂方法模式差不多吗? 其实我的理解是抽象方法模式中,工厂的实现类是将以产品组合为单位的。
上面的例子,两个工厂分别是组合了NormalMaster两种类型,让同一工厂生产的是能配套的产品组合。回到工厂模式的维度,使用者只需要知道什么工厂会给他想要的产品组合。

总结

作为一个细分了三个种类的设计模式,到底该如何取舍?比起直接new一个对象,使用对应模式的好处到底在哪?

  • 简单工厂模式:
    1. 根据传入的参数决定产出的对象,可以隐藏一些创建的细节
    2. 适用于需要根据条件创建不同对象的场景。
  • 工厂方法模式:
    1. 将简单工厂转化为抽象工厂的子类,每个子类负责相应对象的创建,将创建逻辑从简单工厂中解耦到各自实现类。
    2. 适用于要创建的对象会出现扩展的场景;或者是希望将创建逻辑分别封装在具体工厂类的场景。
  • 抽象工厂模式:
    1. 抽象工厂提供接口,用于创建一系列相关或者相互依赖的对象。
    2. 适用于要创建复数种类的对象;或者是希望将创建逻辑封装在具体工厂类的场景。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

闯关leetcode——3178. Find the Child Who Has the Ball After K Seconds

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/find-the-child-who-has-the-ball-after-k-seconds/description/ 内容 You are given two positive integers n and k. There are n children numbered from 0 to n - 1 standing in a queue in o…

Java结合ElasticSearch根据查询关键字,高亮显示全文数据。

由于es高亮显示机制的问题。当全文内容过多,且搜索中标又少时,就会出现高亮结果无法覆盖全文。因此需要根据需求手动替换。 1.根据es的ik分词器获取搜索词的分词结果。 es部分: //中文分词解析 post /_analyze {"analyzer":"…

Python——NumPy库的简单用法,超级详细教程使用

一、什么是NumPy库 NumPy:它是python的一个科学计算库函数,它是由c语言编写的 它应用于数据处理、机器学习、图像处理、文件操作等等 二、array函数 这里导入库numpy,命名为np,后面的np都是代表着是numpy函数 array函数表示创建…

【Java语言】String类

在C语言中字符串用字符可以表示,可在Java中有单独的类来表示字符串(就是String),现在我来介绍介绍String类。 字符串构造 一般字符串都是直接赋值构造的,像这样: 还可以这样构造: 图更能直观的…

自由学习记录(21)

感觉反而 还复杂一点,关系并不纯粹,游戏里用的少...的确 是知道为什么游戏不用了 理解思想就可以了,实际操作也是动态的分析,硬套某种模式也不是怎么很合适 MVC的了解应该是差不多了,重点还是实际中的使用了 所以删了…

Bugku CTF_Web——点login咋没反应

Bugku CTF_Web——点login咋没反应 进入靶场 随便输个试试 看来确实点login没反应 抓包看看 也没有什么信息 看了下源码 给了点提示 一个admin.css try ?12713传参试试 拿到一个php代码 <?php error_reporting(0); $KEYctf.bugku.com; include_once("flag.php&q…

软件测试面试大全(含答案+文档)

1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&…

从华为到创业公司

我有一个朋友&#xff0c;在华为工作了很长一段时间&#xff0c;一年多前&#xff0c;他从华为出来到了一家创业公司。 周末趁着有时间&#xff0c;我跟他聊了下关于从华为到创业公司的一些问题&#xff0c;总结给大伙看看。 ▎1 在华为工作和在创业公司工作最大的差别是什么呢…

Linux网络——网络初识

目录 1. 认识协议 2. 协议的分层 3. OSI 七层模型 && TCP/IP 五层(四层)模型 4. 网络传输的基本流程 5. 以太网的通信原理 6. 数据的跨网络传播 7. 认识 IP 地址 ① IP 是什么 ② IP 与 MAC 的关系 ③ 为什么需要 IP 在谈及网络之前&#xff0c;我们要先对学…

React Hooks在现代前端开发中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 React Hooks在现代前端开发中的应用 React Hooks在现代前端开发中的应用 React Hooks在现代前端开发中的应用 引言 React Hooks …

执行flink sql连接clickhouse库

手把手教学&#xff0c;flink connector打通clickhouse大数据库&#xff0c;通过下发flink sql&#xff0c;来使用ck。 组件版本jdk1.8flink1.17.2clickhouse23.12.2.59 1.背景 flink官方不支持clickhouse连接器&#xff0c;工作中难免会用到。 2.方案 利用GitHub大佬提供…

【机器学习】如何配置anaconda环境(无脑版)

马上就要上机器学习的实验&#xff0c;这里想写一下我配置机器学习的anaconda环境的二三事 一、首先&#xff0c;下载安装包&#xff1a; Download Now | Anaconda 二、打开安装包&#xff0c;一直点NEXT进行安装 这里要记住你要下载安装的路径在哪&#xff0c;后续配置环境…

如何保护 Microsoft 网络免受中间人攻击

一名办公室工作人员收到了一封看似来自供应商的电子邮件&#xff0c;但该邮件被隔离了&#xff0c;用户请求将其释放。这封邮件看起来没什么问题&#xff0c;因此管理员释放了这封邮件。用户点击邮件查看内容&#xff0c;其中包括一张附加发票。 问题就从这里开始&#xff1a;…

Excel筛选的操作教程

用Excel整理数据时&#xff0c;常常要用到筛选功能&#xff0c;很多复杂的数据经过一定条件的筛选后就变得很清晰。筛选也是Excel的一个基本功能之一&#xff0c;你会使用这个功能吗&#xff1f;不会也没关系&#xff0c;接着往下看&#xff0c;接下来就来演示一些Excel表格筛选…

爬虫补环境案例---问财网(rpc,jsdom,代理,selenium)

目录 一.环境检测 1. 什么是环境检测 2.案例讲解 二 .吐环境脚本 1. 简介 2. 基础使用方法 3.数据返回 4. 完整代理使用 5. 代理封装 6. 封装所有使用方法 jsdom补环境 1. 环境安装 2. 基本使用 3. 添加参数形式 Selenium补环境 1. 简介 2.实战案例 1. 逆向目…

JAVA:探索 EasyExcel 的技术指南

1、简述 在 Java 开发中&#xff0c;Excel 文件的读写操作是一项常见的需求。阿里巴巴开源的 EasyExcel 提供了一种高效、简洁的解决方案&#xff0c;特别是在处理大规模数据时表现尤为突出。本文将详细介绍 EasyExcel 的优缺点、应用场景&#xff0c;并通过实例展示其基本用法…

力扣662:二叉树的最大宽度

给你一棵二叉树的根节点 root &#xff0c;返回树的 最大宽度 。 树的 最大宽度 是所有层中最大的 宽度 。 每一层的 宽度 被定义为该层最左和最右的非空节点&#xff08;即&#xff0c;两个端点&#xff09;之间的长度。将这个二叉树视作与满二叉树结构相同&#xff0c;两端…

Elasticsearch基本概念及使用

Elasticsearch 是一个开源的、分布式的全文搜索和分析引擎&#xff0c;基于 Apache Lucene 构建。它提供了快速的搜索能力&#xff0c;支持大规模的数据分析&#xff0c;广泛应用于日志分析、全文搜索、监控系统和商业智能等领域。ES操作指令是基于restAPI构建&#xff0c;也就…

Vue.js 项目创建流程

Vue.js 项目创建流程 以下是一个详细的步骤指南&#xff0c;用于在Windows系统上使用NVM&#xff08;Node Version Manager&#xff09;和npm创建一个新的Vue.js项目。 1. 安装Node.js指定版本 首先&#xff0c;使用NVM安装Node.js的20.18.0版本。 nvm install 20输出示例&…

如何判定linux系统CPU的核心架构

背景 在开发一个项目的时候&#xff0c;需要配置安装PyTorch环境&#xff0c;自己电脑以前下载过这个相关的包&#xff0c;但是是X86架构的&#xff0c;不知道复制到Linux系统后能否直接使用&#xff0c;于是想着去确认一下&#xff0c;并把自己的方法总结一下,自己下载的文件…