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

news2024/11/27 6:40:02

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

工厂模式的问题

在【设计模式-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);
    }

    @Override
    public void show() {
        System.out.println("海军陆战队出现了,坐标为:(" + x + "," + y + ")");
    }

    @Override
    public void attack() {
        System.out.println("海军陆战队攻击,攻击力为:" + attack);
    }
}

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

/**
 * 变形坦克
 */
public class Tank extends MidClassUnit{

    /**
     * 中级兵种
     *
     * @param x
     * @param y
     */
    public Tank(int x, int y) {
        super(x, y);
    }

    @Override
    public void show() {
        System.out.println("变形坦克出现了,坐标为:(" + x + "," + y + ")");
    }

    @Override
    public void attack() {
        System.out.println("变形坦克攻击,攻击力为:" + attack);
    }
}

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

/**
 * 巨型战舰
 */
public class Battleship extends HighClassUnit{

    /**
     * 高级兵种
     *
     * @param x
     * @param y
     */
    public Battleship(int x, int y) {
        super(x, y);
    }

    @Override
    public void show() {
        System.out.println("巨型战舰出现了,坐标为:(" + x + "," + y + ")");
    }

    @Override
    public void attack() {
        System.out.println("巨型战舰攻击,攻击力为:" + attack);
    }
}

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

/**
 * 螳螂
 */
public class Roach extends LowClassUnit{

    /**
     * 低级兵种
     *
     * @param x
     * @param y
     */
    public Roach(int x, int y) {
        super(x, y);
    }

    @Override
    public void show() {
        System.out.println("螳螂出现了,坐标为:(" + x + "," + y + ")");
    }

    @Override
    public void attack() {
        System.out.println("螳螂攻击,攻击力为:" + attack);
    }
}

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

/**
 * 毒液
 */
public class Poison extends MidClassUnit {

    /**
     * 中级兵种
     *
     * @param x
     * @param y
     */
    public Poison(int x, int y) {
        super(x, y);
    }

    @Override
    public void show() {
        System.out.println("毒液出现了,坐标为:(" + x + "," + y + ")");
    }

    @Override
    public void attack() {
        System.out.println("毒液攻击,攻击力为:" + attack);
    }
}

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

/**
 * 猛犸
 */
public class Mammoth extends HighClassUnit {

    /**
     * 高级兵种
     *
     * @param x
     * @param y
     */
    public Mammoth(int x, int y) {
        super(x, y);
    }

    @Override
    public void show() {
        System.out.println("猛犸出现了,坐标为:(" + x + "," + y + ")");
    }

    @Override
    public 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;
    }

    @Override
    public LowClassUnit createLowClassUnit() {
        LowClassUnit unit = new Marine(x, y);
        System.out.println("制造海军陆战队员成功。");
        return unit;
    }

    @Override
    public MidClassUnit createMidClassUnit() {
        MidClassUnit unit = new Tank(x, y);
        System.out.println("制造变形坦克成功。");
        return unit;
    }

    @Override
    public 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;
    }

    @Override
    public LowClassUnit createLowClassUnit() {
        LowClassUnit unit = new Roach(x, y);
        System.out.println("制造蟑螂成功。");
        return unit;
    }

    @Override
    public MidClassUnit createMidClassUnit() {
        MidClassUnit unit = new Poison(x, y);
        System.out.println("制造毒液成功。");
        return unit;
    }

    @Override
    public 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.coloradmin.cn/o/1319033.html

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

相关文章

Pod控制器详解【五】

文章目录 5. Pod控制器详解5.1 Pod控制器介绍5.2 ReplicaSet(RS)5.3 Deployment(Deploy)5.4 Horizontal Pod Autoscaler(HPA)5.5 DaemonSet(DS)5.6 Job5.7 CronJob(CJ) 5. Pod控制器详解 5.1 Pod控制器介绍 Pod是kubernetes的最小管理单元,在kubernetes中&#xf…

雷电4.0.50模拟器Android7.1.2安装xposed框架

官方论坛:https://xdaforums.com/t/official-xposed-for-lollipop-marshmallow-nougat-oreo-v90-beta3-2018-01-29.3034811/ Xposed 有分支 [EdXposed 和 LSPosed] 。 Edxposed框架现在支持android 8.0 - android 9.0 ,如果是android 7.0或更早的版本&…

【unity小技巧】使用三种方式实现瞄准瞄具放大变焦效果

最终效果对比 文章目录 最终效果对比前言第一种办法方法二1. 创建URP环境2. 配置 Universal Render Pipeline Asset3. 这里向我们新建一个无光的ShaderGraph4. 主图配置4. 新建材质,挂载5. 下面是shaderGraph 的连线图6. 新增脚本控制ObjectScreenPosition随着瞄准镜…

安卓端出现https请求失败(转)

背景# 某天早上,正在一个会议时,突然好几个同事被叫出去了;后面才知道,是有业务同事反馈到领导那里,我们app里面某个功能异常。 具体是这样,我们安卓版本的app是禁止截屏的(应该是app里做了拦…

vue3的大致使用

<template><div class"login_wrap"><div class"form_wrap"> <!-- 账号输入--> <el-form ref"formRef" :model"user" class"demo-dynamic" > <!--prop要跟属性名称对应-->…

呜呜呜我要拿Go赢他~ 入门,Go的最简单的 Web 服务器!

前言 继续接入上章节的呜呜呜我要拿Go赢他~ 入门,Go的基础语法! 的文章现在要学的是Go的最简单的 Web 服务器! 补充 上章节的基础语法-方法声明与调用 方法声明 四个部分&#xff1a; 关键字 func方法名字&#xff1a;首字母是否大写决定了作用域参数列表&#xff1a;返回…

C++面试宝典第6题:访问数组和联合体元素

题目 阅读下面的代码段,并给出程序的输出。 (1)访问数组元素。 int a[] = {61, 62, 63, 64, 65, 66}; int *p = (int *)(&a + 1); printf("%d, %d\n", *(a + 1), *(p - 1)); (2)访问联合体元素。 union {short i;char x[2]; }a;a.x[0] = 10; a.x[1] = 1; …

Qt/C++音视频开发60-坐标拾取/按下鼠标获取矩形区域/转换到视频源真实坐标

一、前言 通过在通道画面上拾取鼠标按下的坐标&#xff0c;然后鼠标移动&#xff0c;直到松开&#xff0c;根据松开的坐标和按下的坐标&#xff0c;绘制一个矩形区域&#xff0c;作为热点或者需要电子放大的区域&#xff0c;拿到这个坐标区域&#xff0c;用途非常多&#xff0…

UE5 C++(二)— 游戏架构介绍

架构关系如下&#xff1a; 这里只简单描述下&#xff0c;具体的查看官方文档 AGameMode: AGameMode 是 AGameModeBase 的子类&#xff0c;拥有一些额外的功能支持多人游戏和旧行为。 所有新建项目默认使用 AGameModeBase。 如果需要此额外行为&#xff0c;可切换到从 AGameM…

【LangChain学习之旅】—(3) LangChain快速构建本地知识库的智能问答系统

【LangChain学习之旅】—&#xff08;3&#xff09; LangChain快速构建本地知识库的智能问答系统 项目及实现框架开发框架核心实现机制数据准备及加载加载文本文本的分割向量数据库存储文本的“嵌入”概念向量数据库概念 相关信息获取RetrievalQA生成回答并展示示例小结 Refere…

云服务器部署vue/node项目

此处以阿里云服务器为例&#xff0c;配置的是LNMP环境 vue部署云服务器&#xff1a; 以阿里云服务为例&#xff0c;端口自定义99 1、在 /usr/share/nginx/html/ 该目录下新建文件夹&#xff0c;该文件夹是部署的打好包的前端项目 例&#xff1a; 2、进入nginx目录配置相关配…

【Qt开发流程】之TCP

概述 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输协议。它是互联网协议套件中的一部分&#xff0c;用于在网络上可靠地传输数据。 TCP通过建立连接、数据传输和连接终止三个阶段来进行通信…

音频I2S

前言 基于网上资料对相关概念做整理汇总&#xff0c;部分内容引用自文后文章。 学习目标&#xff1a;简单了解相关概念、相关协议。 1 概述 数字音频接口DAI&#xff0c;即Digital Audio Interfaces&#xff0c;顾名思义&#xff0c;DAI表示在板级或板间传输数字音频信…

ELK(八)—Metricbeat部署

目录 介绍修改配置文件启动 Modulenginx开启状态查询配置Nginx module查看是否配置成功 介绍 Metricbeat 是一个轻量级的开源度量数据收集器&#xff0c;用于监控系统和服务。它由 Elastic 公司开发&#xff0c;并作为 Elastic Stack&#xff08;Elasticsearch、Logstash、Kiba…

Ubuntu18.04安装ffmpeg

前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_C…

解决:AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’

解决&#xff1a;AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’ 文章目录 解决&#xff1a;AttributeError: module scipy.misc has no attribute imsave背景报错问题报错翻译报错位置代码报错原因解决方法方法一 scipy版本回退&#xff08;不推荐&#…

【物联网】EMQX(二)——docker快速搭建EMQX 和 MQTTX客户端使用

一、前言 在上一篇文章中&#xff0c;小编向大家介绍了物联网必然会用到的消息服务器EMQ&#xff0c;相信大家也对EMQ有了一定的了解&#xff0c;那么接下来&#xff0c;小编从这篇文章正式开始展开对EMQ的学习教程&#xff0c;本章节来记录一下如何对EMQ进行安装。 二、使用…

P2P如何使用register_attention_control为UNet的CrossAttention关联AttentionStore

上次的调试到这里了&#xff0c;写完这篇接着看&#xff0c;prepare_latents_ddim_inverted 如何预计算 inversion latents&#xff1a; /home/pgao/yue/FateZero/video_diffusion/pipelines/p2p_ddim_spatial_temporal.py 1. 原始的UNet3D的CrossAttention和SparseCausalAtte…

展示一段比较简单的人工智能自动做模型的程序

人工智能是一种模拟或模仿人类智能的技术。它通过使计算机系统具有一定的认知能力和学习能力&#xff0c;使其能够自动完成一系列复杂的任务。人工智能可以在各个领域应用&#xff0c;包括图像识别、语音识别、自然语言处理、机器学习等。人工智能还可以用于解决各种问题&#…

地平线前端实习一面复盘(加深对var的理解+展开运算符+平拍数组)

目录 前言一&#xff0c;var的作用二&#xff0c;展开运算符三&#xff0c;平拍数组总结 前言 地平线的面试&#xff0c;有提示&#xff0c;很专业&#xff0c;体验很好。 可惜后面未收到消息&#xff0c;但还是要做复盘。收获还是很大的。 一&#xff0c;var的作用 且看下…