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

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

飞机大战

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

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

(敌人抽象类,注意属性的修饰符,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);}@Overridepublic void show() {System.out.println("坦克出现了,坐标是:" + x + "," + y);}
}

(具体实现类,飞机)

/*** 飞机*/
public class AirPlane extends Enemy{public AirPlane(int x, int y) {super(x, y);}@Overridepublic void show() {System.out.println("飞机出现了,坐标是:" + x + "," + y);}
}

(客户端,client)

import java.util.Random;/*** 客户端*/
public class Client {public static void main(String[] args) {// 屏幕宽度是100int 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{@Overridepublic Enemy createEnemy(int screenLength) {return new AirPlane(new Random().nextInt(screenLength), 0);}
}

(坦克工厂)

import java.util.Random;/*** 坦克工厂*/
public class TankFactory implements Factory{@Overridepublic 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);}@Overridepublic void show() {System.out.println("Boss出现了,坐标是:" + x + "," + y);}
}

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

import java.util.Random;/*** Boss工厂*/
public class BossFactory implements Factory {@Overridepublic 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();}// 创建BossFactory boosFactory = new BossFactory();boosFactory.createEnemy(screenLength).show();}
}

执行结果:

在这里插入图片描述

总结

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

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

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

相关文章

cpu飙升问题排查以及解决

1、查看内存占用排行 top -c 2、查看服务器内存使用情况 free -h 3、查看文件夹磁盘空间大小 Linux 查看各文件夹大小命令du -h --max-depth1 (1)查看文件目录一级目录磁盘空间 du -h --max-depth1 (2&#xff09;查看指定文件目录 du sh home --max-depth2 4、Linux下…

【代码】微电网两阶段鲁棒优化经济调度方法(完美复现)matlab-yalmip-cplex/gurobi

程序名称&#xff1a;两阶段鲁棒优化—微电网两阶段鲁棒优化经济调度方法_刘一欣 实现平台&#xff1a;matlab-yalmip-cplex/gurobi 简介&#xff1a;针对微电网内可再生能源和负荷的不确定性&#xff0c;建立了 min-max-min 结构的两阶段鲁棒优化模型&#xff0c;可得到最恶…

DS八大排序之直接插入排序和希尔排序

前言 我们前面几期介绍了线性和非线性的基本数据结构。例如顺序表、链表、栈和队列、二叉树等~&#xff01;本期和接下来的几期我们来详解介绍各个排序的概念、实现以及性能分析&#xff01; 本期内容 排序的概念以及其运用 常见的排序算法 直接插入排序 希尔排序 一、排序的…

“SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价及拓展

近年来&#xff0c;国内外学者在生态系统的敏感性、适应能力和潜在影响等方面开展了大量的生态脆弱性研究&#xff0c;他们普遍将生态脆弱性概念与农牧交错带、喀斯特地区、黄土高原区、流域、城市等相结合&#xff0c;评价不同类型研究区的生态脆弱特征&#xff0c;其研究内容…

Jmeter性能综合实战——签到及批量签到

提取性能测试的三个方面&#xff1a;核心、高频、基础功能 签 到 请 求 步 骤 1、准备工作&#xff1a; 签到线程组 n HTTP请求默认值 n HTTP cookie 管理器 n 首页访问请求 n 登录请求 n 查看结果树 n 调试取样器 l HTTP代理服务器 &#xff08;1&#xff09;创建线…

vue建立组件无校验版

实现功能&#xff1a; 切换&#xff0c;相当于tab 1、非组件代码&#xff1a; <template><div><div class"tabStyle"><div v-for"(item,index) in tabTitle" :key"index" class"bordItemStyle" :class"c…

Spring框架体系及Spring IOC思想

目录 Spring简介Spring体系结构SpringIOC控制反转思想自定义对象容器Spring实现IOCSpring容器类型容器接口容器实现类对象的创建方式使用构造方法使用工厂类的方法使用工厂类的静态方法对象的创建策略对象的销毁时机生命周期方法获取Bean对象的方式通过id/name获取通过类型获取…

Kvm 管理器突然打不开 启动虚拟系统管理器出错: g-dbus-error-quark: GDBus.Error:org.freed

环境&#xff1a; Ubuntu20.04 KVM mobaxterm 11.1 问题描述&#xff1a; 启动虚拟系统管理器出错: g-dbus-error-quark: GDBus.Error:org.freedesktop.DBus.Error.NoReply: Message recipient disconnected from message bus without replying (4)Traceback (most recen…

一文搞定XMLHttpRequest,AJAX,Promise,Axios及操作实战

XMLHttpRequest,AJAX,Promise,Axios都是发送异步请求的工具&#xff0c;只是使用的场合和方式有所不同。都是一种用于创建快速动态网页的技术 1、认识同步请求和异步请求&#xff1f; 1.1、认识同步请求&#xff1f; 1、我们点击淘宝首页的男装&#xff0c;进入男装页面的这…

C++中的模板

模板概论 c提供了函数模板 (function template.) 所谓函数模板&#xff0c;实际上是建立一个通用函 数&#xff0c;其函数类型和形参类型不具体制定&#xff0c;用一个虚拟的类型来代表。这个通用函数 就成为函数模板。凡是函数体相同的函数都可以用这个模板代替&#xff0c;不…

好物分享(领劵优惠好手)

本次分享一个领取领优惠、充值、会员、购物优惠等功能 部分截图 需要的点击下方按钮 前往体验 感谢大家的支持 更多内容请关注微信小程序&#xff0c;源码、插件、模板及时更新

【C++干货铺】STL简述 | string类的使用指南

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 什么是STL STL的版本 STL的六大组件 STL的缺陷 string类 C语言中的字符串 标准库中的string类 string类常用的接口使用指南 string类中常见的构造 strin…

CUDA安装及环境配置——最新详细版

确定安装版本 在安装之前呢&#xff0c;我们需要确定三件事 第一&#xff1a;查看显卡支持的最高CUDA的版本&#xff0c;以便下载对应的CUDA安装包 第二&#xff1a;查看对应CUDA对应的VS版本&#xff0c;以便下载并安装对应的VS版本&#xff08;vs需要先安装&#xff09; 第三…

【vue脚手架配置代理+github用户搜索案例+vue项目中常用的发送Ajax请求的库+slot插槽】

vue脚手架配置代理github用户搜索案例vue项目中常用的发送Ajax请求的库slot插槽 1 vue脚手架配置代理2 github用户搜索案例2.1 静态列表2.2 列表展示2.3 完善案例 3 vue项目中常用的发送Ajax请求的库3.1 xhr3.2 jQuery3.3 axios3.4 fetch3.5 vue-resource 4 slot 插槽4.1 效果4…

【沁恒蓝牙mesh】CH58x 将RTC时钟切换为LSE外部低速时钟

本文主要记录了【沁恒蓝牙mesh】CH58x 如何将RTC时钟切换为外部时钟 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是喜欢记录零碎知识点的小菜鸟。&#x1f60e;&#x1f4dd; 个人主页&#xff1a;欢迎访问我的 Ethernet_Comm 博客主页&#x1f525;&#x1f389;…

实测有效的 8 个顶级Android 数据恢复工具

由于我们现在生活在一个依赖数字数据的时代&#xff0c;当重要文件从我们的 Android 手机中消失时&#xff0c;这将是一场数字噩梦。如果您没有预先备份Android手机上的数据或未能通过备份找到已删除的数据&#xff0c;那么选择最好的Android数据恢复软件是最佳选择。 因此&am…

苹果提醒事项怎么用?几个简单步骤就能学会!

苹果提醒事项可以帮助你轻松管理待办事项&#xff0c;让你更好地安排自己的时间和工作。但是&#xff0c;有些小伙伴可能对如何使用这个功能还有一些疑问。苹果提醒事项怎么用&#xff1f;不要担心&#xff0c;小编将为大家提供使用提醒事项的方法&#xff0c;帮助你学会如何使…

Nginx系列-正向代理和反向代理

Nginx系列-正向代理和反向代理 文章目录 Nginx系列-正向代理和反向代理1. 三个对象2. 两种场景代理2.1. 正向代理2.2. 反向代理 3. 两种场景的对比3.1 为什么叫做反向代理3.2 正向代理和反向代理的作用 1. 三个对象 客户端&#xff1a;发出请求到代理&#xff0c;并接收代理的…

Android : Fragment 传递数据 — 简单应用

示例图&#xff1a; 创建 Fragment new -> Fragment -> Fragment&#xff08;Blank&#xff09; MainActivity.java package com.example.fragmentdemo;import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.FragmentManager; import andro…

C语言每日一题(41)循环队列

力扣 622 循环队列 题目描述 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前…