【设计模式-2.4】创建型——抽象工厂模式

说明:本文介绍设计模式中,创建型设计模式的抽象工厂设计模式;

工厂模式的问题

在【设计模式-2.2】创建型——简单工厂和工厂模式这篇博文中,介绍过飞机大战游戏里,使用简单工厂和工厂模式来创建坦克、飞机、Boss对象。

在这里插入图片描述

如果对象的类型过多,我们就需要创建更多的工厂类,并且如果我们需要对对象进行分类,如按照等级分类,坦克、飞机属于低等敌人,Boss属于高等敌人;按照战斗场景分类,坦克属于陆地,飞机属于天空,Boss可在陆地或者天空。

这就需要我们对现有的工厂类进一步抽取,抽象。

抽象工厂模式

在《秒懂设计模式》这本书中,提供了一种使用场景。如下:

在这里插入图片描述

作者假设某公司需要开发一款星际战争的游戏,游戏中兵种可分为人类与外星怪兽2个族,其中每个族又可分为1级、2级和3级,不同等级的兵种,攻击力、防御力和生命值不同;

(兵种接口)

/*** 兵种抽象类*/
public abstract class Unit {/*** 攻击力*/protected int attack;/*** 防御力*/protected int defence;/*** 生命值*/protected int health;/*** 横坐标*/protected int x;/*** 纵坐标*/protected int y;public Unit(int attack, int defence, int health, int x, int y) {this.attack = attack;this.defence = defence;this.health = health;this.x = x;this.y = y;}/*** 出现*/public abstract void show();/*** 攻击*/public abstract void attack();
}

(低级兵种)

/*** 低级兵种*/
public abstract class LowClassUnit extends Unit{/*** 低级兵种* @param x* @param y*/public LowClassUnit(int x, int y) {super(5, 2, 35, x, y);}
}

(中级兵种)

/*** 中级兵种*/
public abstract class MidClassUnit extends Unit{/*** 中级兵种* @param x* @param y*/public MidClassUnit(int x, int y) {super(10, 8, 80, x, y);}
}

(高级兵种)

/*** 高级兵种*/
public abstract class HighClassUnit extends Unit{/*** 高级兵种* @param x* @param y*/public HighClassUnit(int x, int y) {super(25, 30, 300, x, y);}
}

(人族,低级兵种,海军陆战队)

/*** 海军陆战队*/
public class Marine extends LowClassUnit {public Marine(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("海军陆战队出现了,坐标为:(" + x + "," + y + ")");}@Overridepublic void attack() {System.out.println("海军陆战队攻击,攻击力为:" + attack);}
}

(人族,中级兵种,变形坦克)

/*** 变形坦克*/
public class Tank extends MidClassUnit{/*** 中级兵种** @param x* @param y*/public Tank(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("变形坦克出现了,坐标为:(" + x + "," + y + ")");}@Overridepublic void attack() {System.out.println("变形坦克攻击,攻击力为:" + attack);}
}

(人族,高级兵种,巨型战舰)

/*** 巨型战舰*/
public class Battleship extends HighClassUnit{/*** 高级兵种** @param x* @param y*/public Battleship(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("巨型战舰出现了,坐标为:(" + x + "," + y + ")");}@Overridepublic void attack() {System.out.println("巨型战舰攻击,攻击力为:" + attack);}
}

(怪兽族,低级兵种,螳螂)

/*** 螳螂*/
public class Roach extends LowClassUnit{/*** 低级兵种** @param x* @param y*/public Roach(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("螳螂出现了,坐标为:(" + x + "," + y + ")");}@Overridepublic void attack() {System.out.println("螳螂攻击,攻击力为:" + attack);}
}

(怪兽组,中级兵种,毒液)

/*** 毒液*/
public class Poison extends MidClassUnit {/*** 中级兵种** @param x* @param y*/public Poison(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("毒液出现了,坐标为:(" + x + "," + y + ")");}@Overridepublic void attack() {System.out.println("毒液攻击,攻击力为:" + attack);}
}

(怪兽组,高级兵种,猛犸)

/*** 猛犸*/
public class Mammoth extends HighClassUnit {/*** 高级兵种** @param x* @param y*/public Mammoth(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("猛犸出现了,坐标为:(" + x + "," + y + ")");}@Overridepublic void attack() {System.out.println("猛犸攻击,攻击力为:" + attack);}
}

如果使用工厂模式来设计,那么需要创建6个工厂类,且这些工厂类互相没有联系,因此我们考虑使用抽象工厂模式,如下:

(抽象兵种工厂)

/*** 抽象兵种工厂*/
public interface AbstractFactory {/*** 创建低级兵种* @return*/LowClassUnit createLowClassUnit();/*** 创建中级兵种* @return*/MidClassUnit createMidClassUnit();/*** 创建高级兵种* @return*/HighClassUnit createHighClassUnit();
}

(人类兵种工厂)

/*** 人类兵种工厂*/
public class HumanFactory implements AbstractFactory {/*** 横坐标*/private int x;/*** 纵坐标*/private int y;public HumanFactory(int x, int y) {this.x = x;this.y = y;}@Overridepublic LowClassUnit createLowClassUnit() {LowClassUnit unit = new Marine(x, y);System.out.println("制造海军陆战队员成功。");return unit;}@Overridepublic MidClassUnit createMidClassUnit() {MidClassUnit unit = new Tank(x, y);System.out.println("制造变形坦克成功。");return unit;}@Overridepublic HighClassUnit createHighClassUnit() {HighClassUnit unit = new Battleship(x, y);System.out.println("制造巨型战舰成功。");return unit;}
}

(外星怪兽兵种工厂)

/*** 外星人兵种工厂*/
public class AlienFactory implements AbstractFactory {/*** 横坐标*/private int x;/*** 纵坐标*/private int y;public AlienFactory(int x, int y) {this.x = x;this.y = y;}@Overridepublic LowClassUnit createLowClassUnit() {LowClassUnit unit = new Roach(x, y);System.out.println("制造蟑螂成功。");return unit;}@Overridepublic MidClassUnit createMidClassUnit() {MidClassUnit unit = new Poison(x, y);System.out.println("制造毒液成功。");return unit;}@Overridepublic HighClassUnit createHighClassUnit() {HighClassUnit unit = new Mammoth(x, y);System.out.println("制造猛犸象成功。");return unit;}
}

(客户端,演示人类兵种、怪兽兵种的创建)

/*** 客户端*/
public class Client {public static void main(String[] args) {System.out.println("......人类兵种工厂开始制造兵种......");// 创建人类兵种工厂AbstractFactory humanFactory = new HumanFactory(10, 10);// 创建低级兵种LowClassUnit humanLowClassUnit = humanFactory.createLowClassUnit();// 创建中级兵种MidClassUnit humanMidClassUnit = humanFactory.createMidClassUnit();// 创建高级兵种HighClassUnit humanHighClassUnit = humanFactory.createHighClassUnit();// 低级兵种展示和攻击humanLowClassUnit.show();humanLowClassUnit.attack();// 中级兵种展示和攻击humanMidClassUnit.show();humanMidClassUnit.attack();// 高级兵种展示和攻击humanHighClassUnit.show();humanHighClassUnit.attack();System.out.println("==========================================================");System.out.println("......外星人兵种工厂开始制造兵种......");// 创建外星人兵种工厂AbstractFactory alienFactory = new AlienFactory(200, 200);// 创建低级兵种LowClassUnit alienLowClassUnit = alienFactory.createLowClassUnit();// 创建中级兵种MidClassUnit alienMidClassUnit = alienFactory.createMidClassUnit();// 创建高级兵种HighClassUnit alienHighClassUnit = alienFactory.createHighClassUnit();// 低级兵种展示和攻击alienLowClassUnit.show();alienLowClassUnit.attack();// 中级兵种展示和攻击alienMidClassUnit.show();alienMidClassUnit.attack();// 高级兵种展示和攻击alienHighClassUnit.show();alienHighClassUnit.attack();}
}

以上是抽象工厂模式创建对象的过程。抽象工厂模式是对工厂模式的一种提炼,当我们需要对系统中的对象进行分类区别时,应当考虑使用抽象工厂模式。

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书,代码来自《秒懂设计模式》,略有不同。

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

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

相关文章

MySQL数据库,表的增量备份与恢复

1. 从物理与逻辑的角度 数据库备份可以分为物理备份和逻辑备份。物理备份是对数据库操作系统的物理文件(如数据 文件,日志文件等)的备份。这种类型的备份适用于在出现问题时需要快速恢复的大型重要数据库。 物理备份又可以分为冷备份&#xf…

【JAVA-Day65】Java内部类深度解析

Java内部类深度解析 《Java内部类深度解析》摘要引言一、理解内部类1. 内部类的基本概念和语法1.1 什么是内部类?1.2 内部类的语法结构1.3 内部类的基本概念 2. 不同类型的内部类详解2.1 成员内部类2.2 静态内部类2.3 局部内部类2.4 匿名内部类 二、内部类与普通类的…

【Unity自动寻路】使用Navigation系统实现物体自动寻路绕开障碍物

知识点流程图 自动导航Navigation系统 我们在游戏场景中经常会有一些障碍物、墙壁、树木等等,如果我想要让角色或者怪物去墙的另一边,我直接在墙另一边点击左键,我希望角色自动跑过去,但是他不能直接穿透墙,他需要“智…

04-Nacos中负载均衡规则的配置

负载均衡规则 同集群优先 默认的ZoneAvoidanceRule实现并不能根据同集群优先的规则来实现负载均衡,Nacos中提供了一个实现叫NacosRule可以优先从同集群中挑选服务实例 当服务消费者在本地集群找不到服务提供者时也会去其他集群中寻找,但此时会在服务消费者的控制台报警告 第…

STM32_串口下载程序

目录标题 前言1、理论知识2、串口下载具体操作2.1、硬件准备2.2、软件准备2.3、设置单片机的启动模式为系统存储器启动2.4、软件配置2.5、下载程序 附:生成hex文件 前言 使用调试器下载程序又快有稳定还能使用调试功能,当然是下载调试的首选。但是拓展下串口下载程…

BAQ压缩原理

什么是BAQ? BAQ——Block Adaptive Quantization,块自适应量化 BAQ是一种数据压缩算法。 谁提出了BAQ压缩? BAQ压缩原理是由美国NASA JPL的R. Kwok和W.T.K. Johnson在1989年提出的。第一次被用于美国NASA的“麦哲伦金星探测”任务中。 BAQ压缩的目的是什么? 上世纪后半…

网络爬虫第1天之数据解析库的使用

一、正则表达式 正则表达式(Regular Expression 简称regex或regexp)是一种强大的文本处理工具,它可以帮助实现快速的检索、替换或验证字符串中的特定模式。 1、match match()方法会尝试从字符串开始的位置到字符结束的位置匹配正则表达式&am…

gitee gihub上传步骤

上传 1. 到具体要上传的文件目录 2. 右击git Bash Here 初始化仓库:git init 3. 添加文件 添加所有文件 : git add . (注意这里有个点)添加具体文件: git add test.md 4. 添加到暂存区 git commit -m 暂存区 5. 将本地代…

如何将数据库导入MySQL的办法

在电脑cmd终端进行导入 首先找到MySQL中bin的位置 第一步:找到MySQL 第二步:进入MySQL 第三步:打开bin 第四步:输入cmd进入终端 第五步: 输入mysql -uroot -p 然后会弹出enter password: 输入你的密码…

Day10 Liunx高级系统设计11-数据库2

DQL:数据查询语言 查询全表 select * from 表名; 查询指定列 select 列名 1, 列名 2,… from 表名 ; 条件查询 select * from 表名 where 条件 ; 注意: 条件查询就是在查询时给出 WHERE 子句,在 WHERE 子句中可以使用如下运算符及关键 字&#…

linux笔记--VSCode利用交换机跳转服务器

目录 1--前言 2--VSCode设置 3--ssh连接 1--前言 博主学校的服务器有两个,其中一个服务器(14)可以通过挂内网VPN来进行连接,但另一个服务器(15)即使挂了VPN也不能连接,只能通过内网进行连接。…

ripro后台登录后转圈和图标不显示的原因及解决方法

最近,好多小伙伴使用ripro主题的小伙伴们都发现,登录后台后,进入主题设置就转圈,等待老半天后好不容易显示页面了,却发现图标不显示了,都统一显示为方框。 这是因为后台的js、css这类静态资源托管用的是js…

力扣刷题-二叉树-找树左下角的值

513 找树左下角的值 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 示例 2: 思路 层序遍历 直接层序遍历,因为题目说了是最底层,最左边的值&a…

紫光FPGA DDR3 IP使用和注意事项(axi4协议)

紫光DDR3 IP使用 对于紫光ddr3 IP核的使用需要注意事情。 阅读ddr ip手册: 1、注意:对于写地址通道,axi_awvalid要一直拉高,axi_awready才会拉高。使用的芯片型号时PG2L100H-6FBG676,不同的型号IP核接口和axi的握手协…

IDEA2020关于Cannot resolve symbol ‘servlet‘报错

刚开始也配置了tomcat,但是依然报错,后来查找资料解决了 在项目下面创建一个libs文件夹,然后将tomcat / lib文件夹中的servlet-api.jar复制了过来,然后再添加到library。 具体操作步骤:

Code automatic processing

自动化处理没啥用的代码,测试下,还不错的感觉

Elasticsearch的使用总结

Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。 put/post请求:http://localhost:9200/索引库名称 {"settings":{"index":{"number_of_shards":1, # 分片数量…

风速预测(三)EMD-LSTM-Attention模型

目录 1 风速数据EMD分解与可视化 1.1 导入数据 1.2 EMD分解 2 数据集制作与预处理 2.1 先划分数据集,按照8:2划分训练集和测试集 2.2 设置滑动窗口大小为7,制作数据集 3 基于Pytorch的EMD-LSTM-Attention模型预测 3.1 数据加载&#…

uniapp怎么获取微信步数

微信步数获取的背景 微信步数是指用户在微信运动中记录的步数数据。微信提供了开放能力,允许第三方应用获取用户授权后的微信步数数据,以便进行进一步的数据分析和展示。使用时报错:fail api scope is not declared in the privacy agreemen…

libevent服务GET/POST的简单使用

目录 1、前言2、测试demo2.1、目录结构2.2、 测试源码2.2.1、http_server.cpp2.2.2、 http_server.h 2.3、 编译2.4、 运行结果2.4.1、测试POST2.4.2 、测试GET请求 1、前言 项目开发中经常需要使用到私有协议和Qt,Android等GUI前端通信,比较常用的使用POST和GET方式…