秒懂设计模式--学习笔记(4)【创建篇-工厂方法模式】

news2024/11/18 6:44:41

目录

      • 3、工厂方法模式
          • 3.1 介绍
          • 3.2 工厂的多元化与专业化
          • 3.3 游戏角色建模(建模)
          • 3.4 简单工厂不简单(实例化、初始化)
          • 3.5 制定工业制造标准
          • 3.6劳动分工

3、工厂方法模式

3.1 介绍
  • 程序设计中的工厂类往往是对对象构造、实例化、初始化过程的封装,而工厂方法(Factory Method)则可以升华为一种设计模式
  • 它对工厂制造方法进行接口规范化,以允许子类工厂决定具体制造哪类产品的实例,最终降低系统耦合,使系统的可维护性、可扩展性等得到提升
  • 测试类文件,下面开始进行示例(空战游戏示例)。
    测试类文件目录
3.2 工厂的多元化与专业化
  • 要制造产品(实例化对象)就得用到关键字“new”,例如“Plane plane = newPlane();”,或许还会有一些复杂的初始化代码(硬编码)
  • 当我们不必关心产品的制造过程(实例化、初始化),而将这个任务交由相应的工厂来全权负责时,工厂最终能交付产品供我们使用即可
  • 工厂内部封装的生产逻辑对外部来说像一个黑盒子,外部不需要关心工厂内部细节,外部类只管调用即可
  • 多元化的生产模式,不同的产品可以交由不同的专业工厂来生产,例如皮鞋由皮鞋工厂来制造,汽车则由汽车工厂来制造,专业化分工明确
3.3 游戏角色建模(建模)
  • 敌人的种类有飞机和坦克:有共同的属性或行为,描述位置状态的坐标,以及一个展示(绘制)方法
  • 使用抽象类Enemy来定义所有敌人的父类
package factory.entity;

/**
 * 敌人抽象类
 **/
public abstract class Enemy {
    // 敌人坐标
    protected int x;
    protected int y;

    /**
     * 构造方法:初始化坐标
     * @param x
     * @param y
     */
    public Enemy(int x, int y) {
        this.x = x;
        this.y = y;
    }

    /**
     * 抽象方法,交给子类去实现:在地图上绘制
     */
    public abstract void show();
}

  • 具体子类实现,也就是敌机类Airplane和坦克类Tank
package factory.entity;

import factory.entity.Enemy;

/**
 * 敌机类:继承了敌人抽象类Enemy
 **/
public class Airplane extends Enemy {

    /**
     * 调用父类构造方法初始化坐标
     */
    public Airplane(int x, int y) {
        super(x, y);
    }

    /**
     * 重写父类绘制方法
     */
    @Override
    public void show() {
        System.out.println("绘制飞机于上层图层,出现坐标:" + x + "," + y);
        System.out.println("飞机向玩家发起攻击……");
    }
}
package factory.entity;

import factory.entity.Enemy;

/**
 * 坦克类:继承了敌人抽象类Enemy
 **/
public class Tank extends Enemy {
    /**
     * 调用父类构造方法初始化坐标
     */
    public Tank(int x, int y) {
        super(x, y);
    }

    /**
     * 重写父类绘制方法
     */
    @Override
    public void show() {
        System.out.println("绘制坦克于下层图层,出现坐标:" + x + "," + y);
        System.out.println("坦克向玩家发起攻击……");
    }
}
3.4 简单工厂不简单(实例化、初始化)
  • 产品建模完成后,就应该考虑如何实例化和初始化这些敌人了
  • 客户端测试类,new 实例化和初始化敌机类
package factory.simpleFactory;

import factory.entity.Airplane;
import factory.entity.Tank;
import java.util.Random;

/**
 * 客户端测试类
 **/
public class Client {
    public static void main(String[] args) {
          test1_default();
    }

    /**
     * 输出结果:
     *      游戏开始
     *      绘制飞机于上层图层,出现坐标:22,0
     *      飞机向玩家发起攻击……
     *      绘制坦克于下层图层,出现坐标:52,0
     *      坦克向玩家发起攻击……
     */
    private static void test1_default() {
        // 屏幕宽度:假设屏幕宽度为100
        int screenWidth = 100;
        System.out.println("游戏开始");

        // 准备随机数
        Random random = new Random();

        // 生成敌机横坐标随机数:生成一个从0到“屏幕宽度”的随机数
        int x = random.nextInt(screenWidth);
        // 实例化敌机:以此为横坐标构造并初始化
        Airplane airplane = new Airplane(x, 0);
        airplane.show(); // 显示敌机

        // 坦克横坐标随机数
        x = random.nextInt(screenWidth);
        Tank tank = new Tank(x, 0);
        tank.show();

        // 如果我们还有其他敌人也需要构造的话,那么同样的代码就会再次出现
        // 这些实例化逻辑抽离出来作为一个工厂类
    }
}


  • 然而,制造随机出现的敌人这个动作貌似不应该出现在客户端类中
    • 试想如果我们还有其他敌人也需要构造的话,那么同样的代码就会再次出现,尤其是当初始化越复杂的时候重复代码就会越多
  • 如此耗时费力,何不把这些实例化逻辑抽离出来作为一个工厂类
package factory.simpleFactory;

import factory.entity.Airplane;
import factory.entity.Enemy;
import factory.entity.Tank;
import java.util.Random;

/**
 * 简单工厂类
 *    简单工厂类SimpleFactory将之前在客户端类里制造敌人的代码挪过来
 **/
public class SimpleFactory {
    // 屏幕宽度
    private int screenWidth;
    // 随机数
    private Random random;

    public SimpleFactory(int screenWidth) {
        this.screenWidth = screenWidth;
        this.random = new Random();
    }

    /**
     * 根据传入类型,创建对应的对象实例
     * @param type
     * @return
     */
    public Enemy create(String type) {
        int i = random.nextInt(screenWidth);
        Enemy en = null;
        switch (type) {
            case "Airplane":
                en = new Airplane(i, 0);
                break;
            case "Tank":
                en = new Tank(i, 0);
                break;
        }
        return en;
    }
}
  • 客户端测试类使用简单工厂
	/**
     * 使用简单工厂:客户端测试类的代码变得异常简单、清爽
     * 然而,这个简单工厂的确很“简单”,但并不涉及任何的模式设计范畴。制造逻辑只是被换了个地方
     */
    private static void test2_simpleFactory() {
        System.out.println("游戏开始");
        SimpleFactory simpleFactory = new SimpleFactory(100);
        simpleFactory.create("Airplane").show();
        simpleFactory.create("Tank").show();
    }

  • 简单工厂类SimpleFactory将之前在客户端测试类里制造敌人的代码挪过来
    • 如此一来,制造敌人这个任务就全权交由【简单工厂】来负责了,于是客户端便可以直接从简单工厂取用敌人了
    • 虽然客户端中不再直接出现对产品实例化的代码,但羊毛出在羊身上,制造逻辑只是被换了个地方,挪到了简单工厂中而已
    • 并且客户端还要告知产品种类才能产出,这无疑是另一种意义上的耦合
3.5 制定工业制造标准
  • 针对复杂多变的生产需求,将简单工厂的制造方法进行拆分,构建起抽象化、多态化的生产模式
  • 对各种各样的生产方式(工厂方法)进行抽象,首先定义一个工厂接口,以确立统一的工业制造标准
  • 工厂接口: 确立统一标准,是工厂方法模式的核心
package factory.factoryMethod;

import factory.entity.Enemy;

/**
 * 工厂接口: 确立统一标准,是工厂方法模式的核心
 **/
public interface Factory {
    /**
     * 声明了标准,传入屏幕宽度,任何工厂都应遵循此接口
     * @param screenWidth
     * @return
     */
    Enemy createEnemy(int screenWidth);
}

  • 实现工厂类,关键字implements实现工厂接口Factory
    • 飞机工厂制造飞机
    • 坦克工厂制造坦克
    • 如果需要扩展:基于此模式继续我们的扩展即可: 创建工厂类,同样实现工厂方法接口
      • 关底Boss
package factory.factoryMethod;

import factory.entity.Airplane;
import factory.entity.Enemy;
import java.util.Random;

/**
*  飞机工厂类:以关键字implements声明了本类是实现工厂接口Factory的工厂实现类
**/
public class AirplaneFactory implements Factory{

    /**
     * 具体实现: 飞机工厂制造飞机
     * @param screenWidth
     * @return
     */
    @Override
    public Enemy createEnemy(int screenWidth) {
        Random random = new Random();
        return new Airplane(random.nextInt(screenWidth), 0);
    }
}
package factory.factoryMethod;

import factory.entity.Enemy;
import factory.entity.Tank;

import java.util.Random;

/**
 * 坦克工厂类: 以关键字implements声明了本类是实现工厂接口Factory的工厂实现类
 **/
public class TankFactory implements Factory{

    /**
     * 具体实现:坦克工厂制造坦克
     * @param screenWidth
     * @return
     */
    @Override
    public Enemy createEnemy(int screenWidth) {
        Random random = new Random();
        return new Tank(random.nextInt(screenWidth), 0);
    }
}

package factory.factoryMethod;

import factory.entity.Boss;
import factory.entity.Enemy;

/**
 * 关底BOSS工厂类
 **/
public class BossFactory implements Factory{
    @Override
    public Enemy createEnemy(int screenWidth) {
        // 让Boss出现在屏幕中央
        return new Boss(screenWidth/2, 0);
    }
}
  • 每个工厂的生产策略或方式都具备自己的产品特色,不同的产品需求都能找到相应的工厂来满足,即便没有,我们也可以添加新工厂来解决
  • 使系统具有良好的兼容性和可扩展性
3.6劳动分工
  • 只需添加相应的工厂类,无须再对现有代码做任何更改
  • 工厂方法模式可以被看作由简单工厂演化而来的高级版,后者才是真正的设计模式
  • 在工厂方法模式中,不仅产品需要分类,工厂同样需要分类
  • 工厂方法模式的各角色定义
    • Product(产品):所有产品的顶级父类,可以是抽象类或者接口。如:Enemy
    • ConcreteProduct(子产品):由产品类Product派生出的产品子类,可以有多个产品子类。如:Airplane、Tank、Boss
    • Factory(工厂接口):定义工厂方法的工厂接口,当然也可以是抽象类它使顶级工厂制造方法抽象化、标准统一化。如:Factory
    • ConcreteFactory(工厂实现):实现了工厂接口的工厂实现类,并决定工厂方法中具体返回哪种产品子类的实例。如:AirplaneFactory、AirplaneFactory、BossFactory
  • 明确合理的劳动分工才能真正地促进生产效率的提升

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

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

相关文章

【AIGC评测体系】大模型评测指标集

大模型评测指标集 (☆)SuperCLUE(1)SuperCLUE-V(中文原生多模态理解测评基准)(2)SuperCLUE-Auto(汽车大模型测评基准)(3)AIGVBench-T2…

昇思25天学习打卡营第6天|关于函数与神经网络梯度相关技术探讨

目录 Python 库及 MindSpore 相关模块和类的导入 函数与计算图 微分函数与梯度计算 Stop Gradient Auxiliary data 神经网络梯度计算 Python 库及 MindSpore 相关模块和类的导入 Python 中的 numpy 库被成功导入,并简称为 np。numpy 在科学计算领域应用广泛&#x…

借教室(题解)

P1083 [NOIP2012 提高组] 借教室 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a;二分前缀和 我们将和质检员那题差不多&#xff0c;只需要将候选人二分即可 #include<bits/stdc.h> using namespace std; #define int long long int n,m; int r[100000…

精准检测,守护安全:可燃气体报警器检测范围探讨

随着工业化进程的加快&#xff0c;易燃易爆气体的使用日益普遍&#xff0c;其安全隐患也愈发凸显。可燃气体报警器作为一种重要的安全监测设备&#xff0c;能够在气体泄漏时及时发出警报&#xff0c;预防火灾和爆炸事故的发生。 在这篇文章中&#xff0c;佰德将对可燃气体报警…

Docker搭建MySQL双主复制详细教程

在此之前需要提前安装好Docker和 Docker Compose 。 一、创建目录 首先创建一个本地数据挂载目录。 mkdir -p master1-data master2-data二、编写docker-compose.yml version: 3.7services:mysql-master1:image: mysql:5.7.36container_name: mysql-master1environment:MYSQL_…

自动驾驶---Motion Planning之多段五次多项式

1 前言 在之前的博客系列文章中和读者朋友们聊过Apollo的 Motion Planning方案: 《自动驾驶---Motion Planning之LaneChange》 《自动驾驶---Motion Planning之Path Boundary》 《自动驾驶---Motion Planning之Speed Boundary》 《自动驾驶---Motion Planning之轨迹Path优化》…

Python中解决os.listdir命令读取文件乱序问题方法

Python中使用对话框批量打开文件时出现乱序问题的解决方法 一、问题描述二、os.listdir读取文件乱序问题解决方法 欢迎学习交流&#xff01; 邮箱&#xff1a; z…1…6.com 网站&#xff1a; https://zephyrhours.github.io/ 一、问题描述 有时候为了方便&#xff0c;我们在进…

Hadoop-08-HDFS集群 基础知识 命令行上机实操 hadoop fs 分布式文件系统 读写原理 读流程与写流程 基本语法上传下载拷贝移动文件

章节内容 上一节完成&#xff1a; HDFS的简介内容HDFS基础原理HDFS读文件流程HDFS写文件流程 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&#xff0c;但是没留下…

从零开始学量化~Ptrade使用教程——安装与登录

PTrade交易系统是一款高净值和机构投资者专业投资软件&#xff0c;为用户提供普通交易、篮子交易、日内回转交易、算法交易、量化投研/回测/实盘等各种交易工具&#xff0c;满足用户的各种交易需求和交易场景&#xff0c;帮助用户提高交易效率。 运行环境及安装 操作系统&…

OFDM技术概述8——FBMC

Filter bank multicarrier(FBMC&#xff0c;滤波器组多载波)&#xff0c;是一种类似于OFDM的调制方式&#xff0c;用滤波器抑制子载波的旁瓣大小&#xff0c;使用FFT/IFFT或多相滤波器实现&#xff0c;其应用于5G的主要优势&#xff1a; 子载波信号带限&#xff0c;带外泄漏小…

5.(vue3.x+vite)水平垂直居中实现方式

前端技术社区总目录(订阅之前请先查看该博客) 示例效果 介绍 (1)父级元素设置position:relative; 子级元素设置:position:absolute;left:50%;top:50%;transform: translate(-50%,-50%); 兼容性较好 (1)父级元素设置弹性盒子:display:flex;justify-content:center; a…

LabVIEW幅频特性测试系统

使用LabVIEW软件开发的幅频特性测试系统。该系统整合了Agilent 83732B信号源与Agilent 8563EC频谱仪&#xff0c;通过LabVIEW编程实现自动控制和数据处理&#xff0c;提供了成本效益高、操作简便的解决方案&#xff0c;有效替代了昂贵的专用仪器&#xff0c;提高了测试效率和设…

library source does not match the bytecode for class SpringApplication

library source does not match the bytecode for class SpringApplication 问题描述&#xff1a;springboot源码点进去然后download source后提示标题内容。spring版本5.2.8.RELEASE&#xff0c;springboot版本2.7.18 解决方法&#xff1a;把spring版本改为与boot版本对应的6.…

如何快速去除视频里面的水印字幕等信息?(内附工具)

环境&#xff1a; VSR 需要独显 GPU:N 4070TI 12G 问题描述&#xff1a; 如何快速去除视频里面的水印字幕等信息&#xff1f; 解决方案&#xff1a; 1.打开AI工具VSR&#xff0c;打了要处理的视频 2.右侧滑块调整绿色选框&#xff0c;选中要去的字幕或者水印 这次测试右…

维克日记 v0.4.2:开发者友好的数字化笔记工具

维克日记&#xff0c;专为技术开发者和笔记爱好者设计的数字化笔记工具&#xff0c;以其强大的功能和灵活的配置赢得了用户的好评。软件采用Markdown语法&#xff0c;提供实时预览功能&#xff0c;让您的笔记编辑更加高效和直观。维克日记的用户界面简洁而功能齐全&#xff0c;…

k8s 中间件

1. zookeeper 是的&#xff0c;Zookeeper 和 Kafka 经常一起使用&#xff0c;Zookeeper 在 Kafka 中扮演了关键角色。以下是 Zookeeper 和 Kafka 在实际项目中的结合使用及其作用的详细说明。 项目背景 假设我们有一个分布式数据处理系统&#xff0c;该系统需要高吞吐量的实…

Webpack: 剖析插件基本形态与架构逻辑

概述 Webpack 对外提供了 Loader 与 Plugin 两种扩展方式&#xff0c;其中 Loader 职责比较单一&#xff0c;开发方法比较简单容易理解&#xff1b;Plugin 则功能强大&#xff0c;借助 Webpack 数量庞大的 Hook&#xff0c;我们几乎能改写 Webpack 所有特性&#xff0c;但也伴…

改变图像中特定区域的颜色

背景与原理 再训练施工即系模型中&#xff0c;发现大量施工机械都是黄色的&#xff0c;我需要把它们换成蓝色的&#xff0c;以增强模型使用可靠性。 目前没有尝试深度学习算法&#xff0c;只是简单的进行了处理。 核心目的&#xff1a;通过人工标注与opencv的结合&#xff0…

Cybervadis认证是什么?

Cybervadis认证是一种全面且深入的网络安全评估和认证服务&#xff0c;旨在帮助组织提高其网络安全实践的成熟度&#xff0c;并有效应对不断变化的网络威胁和攻击。以下是关于Cybervadis认证的一些关键信息&#xff1a; 认证目的&#xff1a; 评估和验证组织在网络安全方面的能…

使用目标检测模型YOLO V10 OBB进行旋转目标的检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

这个是在YOLO V10源码的基础上实现的。我只是在源码的基础上做了些许的改动。 YOLO V10源码&#xff1a;YOLO V10源码 YOLOv10是清华大学的研究人员在Ultralytics Python包的基础上&#xff0c;引入了一种新的实时目标检测方法&#xff0c;解决了YOLO 以前版本在后处理和模型架…