工厂方法是一种设计模式,对工厂制造方法进行接口规范化,允许子类工厂决定具体知道哪类产品的实例,最终降低系统耦合,使系统的可维护性、可扩展性等得到提升。

一、工厂的多元化与专业化

要实例化对象,就得用到关键词“new”,例如:Plane plane = new Plane()

或许还有一些复杂的初始化代码,这就是我们常用的传统构造方式。然而这样做的结果会使飞机对象的产生代码被硬编码在客户端类里。

工厂内部的生产逻辑对外部来说像是黑盒子,外部不需关注内部细节,外部类只管调用即可。


二、游戏角色建模

制造产品之前,首先需要建模。例如,飞机和坦克,虽然之间区别比较大,但总有一些共同属性或行为。

1. 我们使用一个抽象类定义所有敌人的父类:

public abstract class Enemy {// 敌人的坐标protected int x;protected int y;// 初始化坐标public Enemy(int x, int y){this.x = x;this.y = y;}// 抽象方法,在地图上绘制public abstract void show();
}

Tips:真实的游戏长江不止这么简单,敌机绘图线程会在下一帧擦除画板并重绘到下一个坐标实现动画效果,敌人抽象类可能还会有move、attack、die等方法,本文先忽略这些细节。

2. 敌机类 Airplane

public class Airplane extends Enemy {public Airplane(int x, int y){super(x, y); // 调用父类构造方法初始化坐标}@Overridepublic void show() {System.out.println("绘制飞机于上层图层,出现坐标: " + x + "," + y);System.out.println("飞机向玩家发起攻击……");}

3. 坦克类 Tank

public class Tank extends Enemy {public Tank(int x, int y){super(x, y); // 调用父类构造方法初始化坐标}@Overridepublic void show() {System.out.println("绘制坦克于下层图层,出现坐标: " + x + "," + y);System.out.println("坦克向玩家发起攻击……");}
}

三、简单工厂不简单

产品建模完整后,就该考虑如何实例化和初始化这些敌人了。要使他们都出现在屏幕最上方,就要使纵坐标y初始化为0,横坐标x随机产生。

我们来看客户端怎样设置:

public class Client {public static void main(String[] args) {int screenWidth = 100; // 屏幕宽度System.out.println("游戏开始");Random random = new Random(); // 准备随机数int x = random.nextInt(screenWidth); // 生成敌机横坐标随机数Enemy airplan = new Airplane(x, 0); // 实例化飞机airplan.show(); // 显示飞机x = random.nextInt(screenWidth); // 坦克同上Enemy tank = new Tank(x, 0);tank.show();}/* 输出结果:游戏开始飞机出现坐标: 94,0飞机向玩家发起攻击……坦克出现坐标: 89,0坦克向玩家发起攻击……*/
}

然而,制造敌机出现的动作,不应该出现在客户端类中。

如果还有很多种敌人,同样的代码会再次出现,尤其是初始化越复杂的时候,重复代码就越多。

如此耗时费力,何不把这些实例化逻辑抽离出来一个工厂类?

按照这个思路,我们来开发一个制造敌人的简单工厂类:

public class SimpleFactory {private int screenWidth;private Random random; // 随机数public SimpleFactory(int screenWidth) {this.screenWidth = screenWidth;this.random = new Random();}public Enemy create(String type) {int x = random.nextInt(screenWidth); // 生成敌人横坐标随机数Enemy enemy = null;switch (type) {case "Airplane":enemy = new Airplane(x, 0); // 实例化飞机break;case "Tank":enemy = new Tank(x, 0); // 实例化坦克break;}return enemy;}
}

简单工厂类SImpleFactory将之前在客户端类里制造敌人的代码挪过来,并封装在第10行的制造方法create方法中,这里我们加了一些逻辑判断,使其可以根据传入的敌机种类(飞机或坦克)生产出相应的对象实例,并随机初始化其位置。

如此以来,制造敌人这个任务就全权交由简单工厂来负责了,客户端可以直接从简单工厂取用敌人了

public class Client {public static void main(String[] args) {System.out.println("游戏开始");SimpleFactory factory = new SimpleFactory(100);factory.create("Airplane").show();factory.create("Tank").show();}
}

如代码所示,客户端类的代码变得异常简单、清爽。

这就是分类封装、各司其职的好处。

虽然客户端中不再直接出现对产品实例化的代码,但羊毛出在羊身上,制造逻辑只是被换了一个地方,挪到了简单工厂中而已,并且客户端还要告知产品种类才能产出,这无疑是另一种意义上的耦合。

除此之外,简单工厂一定要保持简单,否则就不要用简单工厂。

随着游戏项目需求的演变,简单工厂的可扩展性也会变得很差

例如,对于产品种类的判断逻辑,如果有新的敌人类加入,我们就需要再修改简单工厂。随着生产方式不断多元化,工厂类就得不断反复修改,严重缺乏灵活性与可扩展性,尤其对于一些庞大复杂的系统。大量产品逻辑堆积在制造方法中,看起来好像功能强大、无所不能,实际上维护起来举步维艰,简单工厂就会一点也不简单了。


  四、制定工业制造标准

系统中并不是处处都需要调用这样一个万能的“简单工厂”,有时系统只是需要一个坦克对象,所以不必这样大动干戈使用一个这样臃肿的“简单工厂”。

针对复杂多变的生产需求,我们需要对产品制造的相关代码进行合理规划与分类,将简单工厂的制造方法进行拆分,构建起抽象化、多态化的生产模式。下面我们就对各种各样的生产方式(工厂方法)进行抽象。

首先定义一个工厂接口,以确立统一的工业制造标准

public interface Factory {Enemy create(int screenWidth);}

接下来重构一下之前的简单工厂类:

1. 飞机工厂类 AirplaneFactory

public class AirplaneFactory implements Factory {@Overridepublic Enemy create(int screenWidth) {Random random = new Random();return new Airplane(random.nextInt(screenWidth), 0);}
}

2. 坦克工厂类 TankFactory

public class TankFactory implements Factory {@Overridepublic Enemy create(int screenWidth) {Random random = new Random();return new Tank(random.nextInt(screenWidth), 0);}
}

飞机工厂类与坦克工厂类的代码简洁、明了。

都以关键字implements声明了本类是实现工厂接口Factory的工厂实现类,并且在第4行给出了工厂方法create()的具体实现,其中飞机工厂制造飞机,坦克工厂制造坦克,各自有其独特的生产方式。

关键字implements声明了本类是实现工厂接口Factory的工厂实现类,并且在第4行给出了工厂方法create()的具体实现,其中飞机工厂制造飞机,坦克工厂制造坦克,各自有其独特的生产方式。

除了飞机和坦克,应该还会有其他的敌人,当玩家抵达游戏关底时总会有Boss出现,这时候我们该如何扩展呢?显而易见,基于此模式继续我们的扩展即可,先定义一个继承自敌人抽象类Enemy的Boss类,相应地还有Boss的工厂类,同样实现工厂方法接口,请分别参看代码清单

1. 关底Boss类: 

// 代码清单 4-10 关底 Boss 类 Boss
public class Boss extends Enemy {public Boss(int x, int y){super(x, y);}@Overridepublic void show() {System.out.println("Boss出现坐标: " + x + "," + y);System.out.println("Boss向玩家发起攻击……");}
}

2. 关底Boss工厂类

// 代码清单 4-11 关底 Boss 工厂类 BossFactory
public class BossFactory implements Factory {@Overridepublic Enemy create(int screenWidth) {// 让Boss出现在屏幕中央return new Boss(screenWidth / 2, 0);}
}

显而易见,多态化后的工厂多样性不言而喻,每个工厂的生产策略或方式都具备自己的产品特色,不同的产品需求都能找到相应的工厂来满足。

之后若要加入新的敌人类,只需添加相应的工厂类,无须再对现有代码做任何更改。

-- 秒懂设计模式学习笔记

-- 工厂模式

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

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

相关文章

数据应该如何组织,才能让Excel“读懂”?

前言:如果你希望Excel能“读懂”你的数据,就得学会让排序、筛选、数据透视表、函数等这些功能为我们服务。 假设你在和一个非常聪明但有点“死板”的机器人(Excel)对话,你必须用它能理解的语言来组织信息。 “一维表”…

js防止重复提交的3种解决方案

防止 javascript 重复点击和提交的关键方法有三种:1. 禁用按钮法,点击后立即禁用按钮并更改文本提示,请求完成后恢复;2. 节流函数(throttle),限制函数在设定时间间隔内仅执行一次,适…

【信创-k8s】银河麒麟V10国防版+鲲鹏/飞腾(arm64架构)在线/离线部署k8s1.30+kubesphere

银河麒麟作为国家核高基专项的重要成果,国防版凭借其卓越的安全性和可靠性,已成为军工领域的首选操作系统。之前我们在适配麒麟V4国防版的过程中已发现诸多安全性要求,而麒麟V10国防版在安全防护等级上又达到了更高的级别。 本文将主要演示离…

解锁单周期MIPS硬布线:Logisim实战全攻略

目录 一、引言二、MIPS 架构与单周期设计原理2.1 MIPS 架构概述2.2 单周期设计原理剖析 三、Logisim 工具基础3.1 Logisim 简介3.2 基本操作与组件认识 四、单周期 MIPS 硬布线设计步骤4.1 了解 MIPS 指令集4.2 搭建数据通路4.3 设计硬布线控制器4.4 在 Logisim 中创建电路 五、…

7.4.2B+树

B树: (1)每个分支节点最多有m个子树(孩子节点)。 阶:即看当前的B树是几阶B树,就看每个分支节点最多有几个子树,还是看最下一层有几个分叉就是几阶??? 叶子节点:最下边的一层叫叶子…

MFC获取本机所有IP、局域网所有IP、本机和局域网可连接IP

获取本机所有IP地址 // 获取本机所有IP地址 int CMachine::GetLocalIPs(std::vector<CString>& vIPValue) {//返回IP数量&#xff0c; -1表示获取失败vIPValue.clear();int IpNum 0;//1.初始化wsa WSADATA wsaData;int ret WSAStartup(MAKEWORD(2, 2), &wsaD…

【C语言】贪吃蛇小游戏

1. 所需知识 C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API... 2. Win32 API介绍 2.1 Win32 API windows这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外&#xff0c;它同时也是一个很大的服务中心&#xff0c;调用这个服务中心的各种…

PostgreSQL 容器化分布式技术方案

&#x1f4cb; 目录 引言&#xff1a;为什么选择容器化PostgreSQLPostgreSQL容器化基础分布式架构设计高可用实现方案读写分离架构动态扩缩容策略生产环境实践总结与展望 引言&#xff1a;为什么选择容器化PostgreSQL 在数字化转型的浪潮中&#xff0c;数据库作为企业的"…

NV025NV033美光固态闪存NV038NV040

美光固态闪存技术突破与市场布局深度解析 一、技术突破&#xff1a;232层NAND闪存与高密度存储的革新 美光NV系列固态闪存的核心竞争力源于其232层NAND闪存技术&#xff0c;这一技术通过垂直堆叠工艺&#xff0c;将存储单元层层叠加&#xff0c;宛如在指甲盖面积内构建超过20…

Matplotlib 绘图库从入门到精通:Python 数据可视化全解析

引言 在数据科学的世界里&#xff0c;"一图胜千言" 这句话有着深刻的含义。数据可视化不仅是数据分析师展示成果的重要手段&#xff0c;更是数据科学家探索数据、发现规律的强大工具。Matplotlib 作为 Python 生态系统中最著名的数据可视化库&#xff0c;为我们提供…

北斗导航 | 基于CNN-LSTM-PSO算法的接收机自主完好性监测算法

接收机自主完好性监测 原理概述1. 算法架构2. 核心创新点3. 工作流程数学模型1. CNN特征提取2. LSTM时序建模3. PSO优化决策MATLAB完整代码算法优势性能对比应用场景扩展方向原理概述 1. 算法架构 #mermaid-svg-fITV6QrXL1fNYFwG {font-family:"trebuchet ms",verda…

【微信小程序】9、用户拒绝授权地理位置后再次请求授权

1、获取用户当前的地理位置 在本专栏的上一篇文章中讲了如何 获取用户当前的地理位置 首次请求 wx.getLocation API 后&#xff0c;会拉起用户授权界面 但这时用户可能会拒绝授权&#xff0c;当你再次请求 wx.getLocation API 后&#xff0c;没有任何效果。 2、打开设置 用…

嵌入式Linux驱动开发基础-1 hello驱动

1:APP打开的文件在内核中如何表示 1.1 APP 打开文件时&#xff0c;可以得到一个整数&#xff0c;这个整数被称为文件句柄。对于 APP 的每一个文件句柄&#xff0c;在内核里面都有一个“struct file ”与之对应 当我们使用 open 打开文件时&#xff0c;传入的 flags 、 mode…

目标跟踪存在问题以及解决方案

3D 跟踪 一、数据特性引发的跟踪挑战 1. 点云稀疏性与远距离特征缺失 问题表现&#xff1a; 激光雷达点云密度随距离平方衰减&#xff08;如 100 米外车辆点云数不足近距离的 1/10&#xff09;&#xff0c;导致远距离目标几何特征&#xff08;如车轮、车顶轮廓&#xff09;不…

JavaSE-JDK安装

目录 一.在官网下载安装包 二.安装JDK 三.检测JDK是否安装成功 四.配置系统环境变量 一.在官网下载安装包 Oracle官网https://www.oracle.com/cn/java/technologies/downloads/ 二.安装JDK 1.首先在C盘以为的其他盘中创建一个自己可以找到的存放JDK路径&#xff1a; 2.双击下…

使用docker搭建redis主从架构,一主2从

使用Docker搭建Redis主从架构&#xff08;一主两从&#xff09; Redis主从架构是提高系统可用性和读取性能的重要方案&#xff0c;通过Docker可以快速搭建该架构。下面将详细介绍搭建步骤。 架构设计 我们将搭建包含以下组件的架构&#xff1a; 1个主节点&#xff08;Maste…

机器学习3——参数估计之极大似然估计

参数估计 问题背景&#xff1a; P ( ω i ∣ x ) p ( x ∣ ω i ) P ( ω i ) p ( x ) p ( x ) ∑ j 1 c p ( x ∣ ω j ) P ( ω j ) \begin{aligned} & P\left(\omega_i \mid \mathbf{x}\right)\frac{p\left(\mathbf{x} \mid \omega_i\right) P\left(\omega_i\right)…

Spring AOP Pointcut 表达式的语法是怎样的?(execution(...) 是最常用的,还有哪些

Pointcut 表达式是 AOP 的核心&#xff0c;我将详细解析最常用的 execution 表达式&#xff0c;并介绍其他几种同样非常有用的表达式。 1. execution 指示符 (最常用&#xff0c;最强大) execution 用于匹配方法的执行&#xff08;Join Point&#xff09;。它的语法结构最为完…

基于 SpringBoot+Vue 的台球厅管理系统的设计与实现(毕业论文)

基于 SpringBootVue 的台球厅管理系统的设计与实现&#xff08;模板&#xff09;[三号宋体加粗&#xff0c;居中] 摘 要[首行缩进2字符&#xff0c;五号黑体加粗]&#xff1a;摘要内容[五号楷体]本文所提出的基于J2EE/EJB标准的电子化采购平台及其CRM组件综合解决方案&#xf…

运营医疗信息化建设的思路

医疗机构加强运营管理&#xff0c;必须依赖强有力的医院信息系统。信息化很重要&#xff0c;但不能为了信息化而信息化。运营信息化必须有明确的建设目标。 运营信息化建设的目标&#xff0c;包括几个方面&#xff1a; 1.实时反映业务&#xff1b; 2.体现内控思维&#xff1b…