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

    @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();
    }
}

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

总结

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

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

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

相关文章

解读Amazon Q | 用AI聊天机器人连接你与未来的无限可能

授权声明:本篇文章授权活动官方亚马逊云科技文章转发、改写权,包括不限于在 亚马逊云科技开发者社区, 知乎,自媒体平台,第三方开发者媒体等亚马逊云科技官方渠道 在美国当地时间11月28日,亚马逊云科技在拉斯维加斯举办…

vue中实现使用相框点击拍照,canvas进行前端图片合并下载

拍照和相框合成,下载图片dome 一、canvas介绍 Canvas是一个HTML5元素,它提供了一个用于在网页上绘制图形、图像和动画的2D渲染上下文。Canvas可以用于创建各种图形,如线条、矩形、圆形、文本等,并且可以通过JavaScript进行编程操作。 Canvas元素本身是一个矩形框,可以通…

【JavaScript】闭包的理解

闭包是指在一个函数内部创建另一个函数,并且内部函数可以访问外部函数的变量、参数以及其他内部函数,即使外部函数已经执行完毕。这种机制使得内部函数保留了对外部作用域的引用,即使外部作用域已经不再活跃。 为什么闭包重要? 闭…

Python之初识类与对象

类的概念与定义 在生活中,我们走在路边,看到一辆车,大脑中首先想到的是“这是一辆车,然后才是这是一辆什么牌子的车”,在这里,我们就用到了编程中的类的概念。同样的,看到一条小狗,…

php 使用box打包

1.安装box 2.检查是否安装成功 3.查看路径,把路径添加到环境变量,方便使用 4.php项目根目录增加box.json配置文件 5.运行命令生成。这个是在cmd中运行的,记得切换到php源码目录 6.使用 php FastAdmin.phar运行。 说明:如果是常驻…

LVS-DR模式部署

实验准备: 节点服务器 192.168.116.20 #web1 192.168.116.30 #web2 1.部署NFS共享存储 2.部署Web节点服务器 将两台服务器的网关注释掉 #重启网卡 systemctl restart network 修改节点服务器的内核参数|vim /etc/sysctl.conf net.ipv4.conf.lo.arp_ign…

WPF——命令commond的实现方法

命令commond的实现方法 属性通知的方式 鼠标监听绑定事件 行为:可以传递界面控件的参数 第一种: 第二种: 附加属性 propa:附加属性快捷方式

大厂痴迷DDD:从高德portal重构,看DDD的巨大价值

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中,最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题: 谈谈你的DDD落地经验? 谈谈你对DDD的理解&#x…

Vim入门

Vim使用入门 1.Vim编辑器的三种常用模式 一般模式:刚打开文件是它,从编辑模式按“ESC”退回的模式也是它。可以执行各种编辑操作,如移动光标、复制、粘贴、删除、查找替换等 ; 编辑模式:在一般模式下按下 i、I、a、A、o、O 等键…

JavaScript 事件冒泡与捕获机制 --- 带动态图理解

&#xff08;1&#xff09;.事件捕获 从根元素往上传递 --- ---&#xff08;由外到内&#xff09; &#xff08;2&#xff09;.事件冒泡 从元素传递到它的根源素 --- --- &#xff08;由内到外&#xff09; 代码&#xff1a; <!DOCTYPE html> <html lang"en&q…

Linux(操作系统)面经——part 1(持续更新中......)

1、说一说常用的 Linux 命令 mkdir创建文件夹&#xff0c;touch创建文件&#xff0c;mv移动文件内容或改名 rm-r 文件名&#xff1a;删除文件 cp拷贝&#xff1a;cp 文件1 文件2&#xff0c;cp-r跨目录拷贝 cp-r 路径1 路径2 vi 插入 &#xff1a;wqb保存退出 :q!强制退出…

k8s - container

1、容器的生命周期&#xff1a; (1) 简介&#xff1a; Kubernetes 会跟踪 Pod 中每个容器的状态&#xff0c;就像它跟踪 Pod 总体上的阶段一样。 可以使用容器生命周期回调&#xff0c;在容器生命周期中的特定状态点触发事件。 ● 容器生命周期回调&#xff1a; 在容器的生…

【员工工资册】————大一期末答辩近满分作业分享

前言 大家好吖&#xff0c;欢迎来到 YY 滴项目系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C语言的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; PS&#xff1a;以下内容是部分展示&am…

MetaAI语音翻译大模型Seamless登场,主打AI无缝同声传译

论文题目&#xff1a; Seamless: Multilingual Expressive and Streaming Speech Translation 论文链接&#xff1a; https://ai.meta.com/research/publications/seamless-multilingual-expressive-and-streaming-speech-translation/ 代码链接&#xff1a; GitHub - facebook…

STL容器之string(上)

目录 什么是STL string类 string类常见接口 string类的常见构造函数 string类对象的容器操作 string类对象的访问及遍历操作 string类对象的修改操作 拓展 从本期开始&#xff0c;我们将正式学习C中的STL&#xff0c;美国的麦克阿瑟将军说过&#xff1a;“C不能没有STL就…

游戏运行中突然掉线是什么原因导致的

游戏平稳运行的原因只有一个&#xff0c;掉线的原因各有个的不同。这些不同的原因有常见&#xff0c;也有不常见的。但不管出于什么原因的掉线&#xff0c;带来的损失又是相同的。 首先最常见的原因就是攻击造成的 像CC&#xff0c;DDOS。CC会造成服务器资源的浪费&…

深入理解 Goroutines 和 Go Scheduler

本文将重点帮助您了解 Golang 中的 goroutines。Go 调度程序如何工作以在 Go 中实现最佳并发性能。我会尽力用简单的语言解释,这样你就可以理解了。 我们将介绍什么是操作系统中的线程和进程,什么是并发,为什么实现并发很难,以及 goroutines 如何帮助我们实现并发。然后,…

专业面试刷题网站程序源码

介绍&#xff1a; 一个干净的面试刷题网站&#xff01;专业面试刷题网站&#xff0c;助你成为面试达人&#xff01;支持自由组卷、在线刷题、校招社招斩获大厂offer&#xff0c;求职必备! 用这个刷题代码&#xff0c;助你早日打进狼厂、鹅厂等各大厂&#xff0c;薪水直接等级…

Python装饰器新境界:详解装饰器重载内置操作

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python装饰器新境界&#xff1a;详解装饰器重载内置操作&#xff0c;全文3900字&#xff0c;阅读大约15分钟。 Python装饰器重载内置操作&#xff0c;我们通常指的是使用装饰…

P5729 【深基5.例7】工艺品制作

题目描述 现有一个长宽高分别为 w,x,h 组成的实心玻璃立方体&#xff0c;可以认为是由 111 的数个小方块组成的&#xff0c;每个小方块都有一个坐标 (i,j,k)。现在需要进行 &#xfffd;q 次切割。每次切割给出(x1​,y1​,z1​),(x2​,y2​,z2​) 这 6 个参数&#xff0c;保证…