【设计模式-2.2】创建型——简单工厂和工厂模式

news2024/11/23 16:29:19

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

飞机大战

创建型设计模式,关注于对象的创建,本文介绍的简单工厂和工厂模式同样也是。举一个游戏例子,如飞机大战游戏中,屏幕中敌人类型有坦克、飞机,会随机出现在画面的上方;

在这里插入图片描述
我们可以简单的将敌人抽象为一个抽象类,然后分别创建对应的实现类,如下:

(敌人抽象类,注意属性的修饰符,protected,子类中需要用到)

/**
 * 敌人抽象类
 */
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();
}

(具体实现类,坦克)

/**
 * 坦克
 */
public class Tank extends Enemy{

    public Tank(int x, int y) {
        super(x, y);
    }

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

(具体实现类,飞机)

/**
 * 飞机
 */
public class AirPlane extends Enemy{

    public AirPlane(int x, int y) {
        super(x, y);
    }

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

(客户端,client)

import java.util.Random;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 屏幕宽度是100
        int screenLength = 100;

        // 创建坦克
        Enemy tank = new Tank(new Random().nextInt(screenLength),0);
        tank.show();

        // 创建飞机
        Enemy airPlane = new AirPlane(new Random().nextInt(screenLength),0);
        airPlane.show();
    }
}

执行结果:

在这里插入图片描述

分析:以上创建方式,有两点不足之处,对象的创建和使用在一起,耦合性太高;创建对象的代码放到了客户端类里,如果需要创建多个对象的话,客户端的代码势必会越来越臃肿

简单工厂

为了解决上面提到的两个问题,耦合性高,客户端代码臃肿,我们可以使用简单工厂对上面的流程进行改进。如下,创建一个简单工厂类,将创建对象的步骤抽取到这里面:

import java.util.Random;

/**
 * 简单工厂
 */
public class SimpleFactory {

    /**
     * 屏幕宽度
     */
    private int screenLength;

    /**
     * 随机数
     */
    private Random random;

    /**
     * 构造函数
     *
     * @param screenLength
     */
    public SimpleFactory(int screenLength) {
        this.screenLength = screenLength;
        this.random = new Random();
    }

    /**
     * 创建敌人
     * @param type
     * @return
     */
    public Enemy createEnemy(String type) {
        int x = random.nextInt(screenLength);
        Enemy enemy = null;
        switch (type) {
            case "Tank":
                enemy = new Tank(x, 0);
                break;
            case "AirPlane":
                enemy = new AirPlane(x, 0);
                break;
            default:
                throw new RuntimeException("unknown enemy type");
        }
        return enemy;
    }
}

这样,客户端就可以使用这个简单工厂来创建对象了,如下:

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        int screenLength = 100;
        new SimpleFactory(screenLength).createEnemy("Tank").show();
        new SimpleFactory(screenLength).createEnemy("AirPlane").show();
    }
}

执行结果:

在这里插入图片描述
分析:通过简单工厂,对对象的创建进行了封装,使客户端的代码简单、清爽。但是,如果需要增加敌人类型的话,我们就需要去修改这个简单工厂类,新增case分支,这不利于后续的代码扩展

工厂模式

使用工厂模式,可以弥补简单工厂的缺点。我们可以创建一个工厂接口,让后续所有的敌人对象都实现这个接口,并实现其抽象方法,把对象的创建放到具体实现类中,这样后续无论新增多少种敌人类型,都只要实现这个接口即可,不需要对原有系统进行修改。如下:

(工厂接口)

/**
 * 敌人工厂接口
 */
public interface Factory {

    /**
     * 创建敌人
     * 
     * @param screenLength
     * @return
     */
    Enemy createEnemy(int screenLength);
}

(飞机工厂)

import java.util.Random;

/**
 * 飞机工厂
 */
public class AirPlaneFactory implements Factory{

    @Override
    public Enemy createEnemy(int screenLength) {
        return new AirPlane(new Random().nextInt(screenLength), 0);
    }
}

(坦克工厂)

import java.util.Random;

/**
 * 坦克工厂
 */
public class TankFactory implements Factory{

    @Override
    public Enemy createEnemy(int screenLength) {
        return new Tank(new Random().nextInt(screenLength), 0);
    }
}

现在,如果需要新增一个Boss对象,只需要创建对应的Boss对象,及其工厂实现类即可,如下:

(Boss类)

/**
 * Boss
 */
public class Boss extends Enemy{

    public Boss(int x, int y) {
        super(x, y);
    }

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

(Boss工厂实现类,用于创建Boss)

import java.util.Random;

/**
 * Boss工厂
 */
public class BossFactory implements Factory {

    @Override
    public Enemy createEnemy(int screenLength) {
        // Boss出现在屏幕正中间
        return new Boss(screenLength / 2, 0);
    }
}

(客户端代码,客户端只需创建工厂对象,调用其方法即可)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 屏幕宽度
        int screenLength = 100;

        // 创建坦克
        Factory tankFactory = new TankFactory();
        for (int i = 0; i < 10; i++) {
            tankFactory.createEnemy(screenLength).show();
        }

        // 创建飞机
        Factory airFactory = new AirPlaneFactory();
        for (int i = 0; i < 10; i++) {
            airFactory.createEnemy(screenLength).show();
        }

        // 创建Boss
        Factory boosFactory = new BossFactory();
        boosFactory.createEnemy(screenLength).show();
    }
}

执行结果:

在这里插入图片描述

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

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

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

相关文章

android viewpager 禁止滑动

android viewpager 禁止滑动 前言一、viewpager 禁止滑动是什么&#xff0c;有现成方法吗&#xff1f;二、使用setOnTouchListener三、使用自定义viewpager总结 前言 本文介绍了本人有一个相关的需求需要实现这一功能&#xff0c;在过程中发现自己之前没做过&#xff0c;然后记…

【带头学C++】----- 八、C++面向对象编程 ---- 8.5 struct结构体类型增强使用说明

目录 8.5 struct结构体类型增强使用说明 8.5.1 C结构体可以定义成员函数 8.5.2 c中定义结构体变量可以不加struct关键字 8.6 bool布尔类型关键字 8.5 struct结构体类型增强使用说明 第六章对结构体的使用、内存对齐以及数组、深拷贝和浅拷贝进行了一个详细的说明&#xff0c…

统信UOS_麒麟KYLINOS上使用远程SSH连接的工具electerm

原文链接&#xff1a;统信UOS/麒麟KYLINOS上使用SSH工具electerm Hello&#xff0c;大家好啊&#xff01;在我们日常的工作和学习中&#xff0c;远程控制和管理服务器已经成为一项常见且必要的技能。尤其是对于IT专业人士和开发者来说&#xff0c;一个高效、稳定的远程SSH连接工…

智能AI系统ChatGPT网站系统源码+Midjourney绘画+支持DALL-E3文生图,支持最新GPT-4-Turbo模型

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…

漏洞扫描-德迅云安全漏洞扫描服务

漏洞扫描是指基于漏洞数据库&#xff0c;通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测&#xff0c;发现可利用漏洞的一种安全检测的行为。 漏洞扫描的主要目的是发现系统、网络或应用程序中可能存在的安全漏洞和缺陷&#xff0c;以便及时修复这些漏洞和缺…

基于STM32单片机的智能家居系统设计(论文+源码)

1.系统设计 基于STM32单片机的智能家居系统设计与实现的具体任务&#xff1a; &#xff08;1&#xff09;可以实现风扇、窗帘、空调、灯光的开关控制&#xff1b; &#xff08;2&#xff09;具有语音识别功能&#xff0c;可以通过语音控制家电&#xff1b; &#xff08;3&a…

Pytorch:torch.utils.data.DataLoader()

如果读者正在从事深度学习的项目&#xff0c;通常大部分时间都花在了处理数据上&#xff0c;而不是神经网络上。因为数据就像是网络的燃料&#xff1a;它越合适&#xff0c;结果就越快、越准确&#xff01;神经网络表现不佳的主要原因之一可能是由于数据不佳或理解不足。因此&a…

【人工智能】人工智能的技术研究与安全问题的深入讨论

前言 人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI。 它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。人工智能是新一轮科技革命和产业变革的重要驱动力量。 &#x1f4d5;作者简介&#x…

vscode注释插件「koroFileHeader」

前言 在vscode上进行前端开发&#xff0c;有几个流行的注释插件&#xff1a; Better CommentsTodo TreekoroFileHeaderDocument ThisAuto Comment Blocks 在上面的插件中我选择 koroFileHeader 做推荐&#xff0c;原因一是使用人数比较多&#xff08;最多的是 Better Commen…

029 - STM32学习笔记 - ADC(三) 独立模式单通道DMA采集

029 - STM32学习笔记 - 单通道DMA采集&#xff08;三&#xff09; 单通道ADC采集在上节中学习完了&#xff0c;这节在上节的内容基础上&#xff0c;学习单通道DMA采集。程序代码以上节的为基础&#xff0c;需要删除NVIC配置函数、中段服务子程序、R_ADC_Mode_Config()函数中使能…

探索Python内置类属性__repr__:展示对象的魅力与实用性

概要 在Python中&#xff0c;每个对象都有一个内置的__repr__属性&#xff0c;它提供了对象的字符串表示形式。这个特殊的属性在调试、日志记录和交互式会话等场景中非常有用。本文将详细介绍__repr__属性的使用教程&#xff0c;包括定义、常见应用场景和注意事项&#xff0c;…

机器人向前冲

欢迎来到程序小院 机器人向前冲 玩法&#xff1a;一直走动的机器人&#xff0c;点击鼠标左键进行跳跃&#xff0c;跳过不同的匝道&#xff0c;掉下去即为游戏接续&#xff0c; 碰到匝道铁钉游戏结束&#xff0c;一直往前冲吧^^。开始游戏https://www.ormcc.com/play/gameStart…

C++基础 -10- 类的构造函数

类的构造函数类型一 使用this指针给类内参数赋值 class rlxy {public:int a;rlxy(int a, int b, int c){this->aa;this->bb;this->cc;cout << "rlxy" << endl;}protected:int b;private:int c; };int main() {rlxy ss(10, 20, 30); }类的构造…

使用Accelerate库在多GPU上进行LLM推理

大型语言模型(llm)已经彻底改变了自然语言处理领域。随着这些模型在规模和复杂性上的增长&#xff0c;推理的计算需求也显著增加。为了应对这一挑战利用多个gpu变得至关重要。 所以本文将在多个gpu上并行执行推理&#xff0c;主要包括&#xff1a;Accelerate库介绍&#xff0c;…

在Rust中处理命令行参数和环境变量

1.摘要 Rust的命令行和环境变量处理在标准库中提供了一整套实现方法, 在本文中除了探索标准库的使用方法之外, 也在不断适应Rust独有的语法特点。在本文中, 我们通过标准库函数的返回值熟悉了迭代器的使用方法, 操作迭代器精确控制保存的内容, 包括字符串和键值对的使用方法。…

SpringBoot整合EasyExcel实现复杂Excel表格的导入导出功能

文章目录 &#x1f389;SpringBoot整合EasyExcel实现复杂Excel表格的导入&导出功能 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;该系列文章专栏&#xff1a;架构设计&#x1f4dc;其他专栏&#xff1a;Java学习路线 Jav…

mysql 性能排查

mysql 下常见遇到的问题有&#xff0c;mysql连接池耗尽&#xff0c;死锁、慢查、未提交的事务。等等我们可能需要看&#xff1b;我们想要查看的可能有 1.当前连接池连接了哪些客户端&#xff0c;进行了哪些操作 2.当前造成死锁的语句有哪些&#xff0c;是哪个客户端上的&#x…

2023网络安全产业图谱

1. 前言 2023年7月10日&#xff0c;嘶吼安全产业研究院联合国家网络安全产业园区&#xff08;通州园&#xff09;正式发布《嘶吼2023网络安全产业图谱》。 嘶吼安全产业研究院根据当前网络安全发展规划与趋势发布《嘶吼2023网络安全产业图谱》调研&#xff0c;旨在进一步了解…

2020年6月16日 Go生态洞察:泛型的下一步

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

选择跨网数据摆渡系统时,你最关注的功能是哪些?

为什么要选择跨网数据摆渡系统呢&#xff1f;因为做了网络隔离后&#xff0c;要有数据交互。那为什么要做网络隔离呢&#xff1f;主要还是安全方面的考虑&#xff0c;一般有以下几个原因&#xff1a; 1、数据安全保护&#xff1a;对于一些重要数据&#xff0c;比如代码数据、隐…