Java实现常见的工厂模式(包含在Springboot中实战开发)

news2024/11/15 2:08:15

Java实现工厂模式

文章目录

  • Java实现工厂模式
    • 1. 概念
    • 2. 工厂模式的三种实现方式
      • 2.1 简单工厂模式
        • 1.定义产品接口
        • 2. 实现具体产品类
        • 3. 实现简单工厂类
        • 4. 客户端代码
        • 5.运行结果
      • 2.2 工厂方法模式
        • 1. 定义产品接口
        • 2. 实现具体产品类
        • 3. 创建工厂接口
        • 4. 实现具体工厂类
        • 5. 客户端代码
        • 6. 运行结果
      • 2.3 抽象工厂模式
        • 1. 创建家具的抽象产品接口
        • 2. 创建具体产品类
        • 3.创建抽象工厂类
        • 4. 实现具体的工厂类
        • 5. 客户端代码
        • 6. 运行结果
    • 3. 三种方式的优缺点对比总结
      • 4.SpringBoot中工厂模式实战
      • 5. 结论

1. 概念

定义:工厂模式(Factory Pattern)是一种创建型设计模式,定义了一个创建对象的接口,但由子类来决定实例化哪个具体类。
使用场景
需要生成复杂对象,但不希望客户端依赖这些对象的具体类时。
当多个类具有相似功能,但只在某些细节上有区别时,工厂模式能够统一这些不同点。

2. 工厂模式的三种实现方式

通常有三种实现方式:简单工厂模式、工厂方法模式、抽象工厂模式。

举个生活中的例子:假设你有一个家具公司,你可以生产两种风格的家具——现代风格和维多利亚风格,每种风格都有沙发、椅子等家具

2.1 简单工厂模式

简单工厂将所有创建产品的逻辑集中在一个工厂类中。我们可以基于家具厂的案例,使用简单工厂模式来实现家具的创建。
在这里插入图片描述

概念:简单工厂模式由一个工厂类根据传入的参数,决定创建哪一种产品对象。它不属于23种经典的设计模式,但经常作为工厂模式的基础。

1.定义产品接口
// 椅子接口
interface Chair {
    void create();
}

// 沙发接口
interface Sofa {
    void create();
}
2. 实现具体产品类

分别实现现代风格和维多利亚风格的椅子和沙发。

// 现代风格的椅子
class ModernChair implements Chair {
    @Override
    public void create() {
        System.out.println("创建了一张现代风格的椅子");
    }
}

// 维多利亚风格的椅子
class VictorianChair implements Chair {
    @Override
    public void create() {
        System.out.println("创建了一张维多利亚风格的椅子");
    }
}

// 现代风格的沙发
class ModernSofa implements Sofa {
    @Override
    public void create() {
        System.out.println("创建了一张现代风格的沙发");
    }
}

// 维多利亚风格的沙发
class VictorianSofa implements Sofa {
    @Override
    public void create() {
        System.out.println("创建了一张维多利亚风格的沙发");
    }
}

3. 实现简单工厂类

这里我们创建一个工厂类 FurnitureFactory,它根据传入的参数来创建不同类型的家具。

// 简单家具工厂类
class FurnitureFactory {
    // 静态方法,根据产品类型创建相应的家具
    public static Chair createChair(String type) {
        if (type.equalsIgnoreCase("modern")) {
            return new ModernChair();
        } else if (type.equalsIgnoreCase("victorian")) {
            return new VictorianChair();
        } else {
            throw new IllegalArgumentException("未知的椅子类型: " + type);
        }
    }

    public static Sofa createSofa(String type) {
        if (type.equalsIgnoreCase("modern")) {
            return new ModernSofa();
        } else if (type.equalsIgnoreCase("victorian")) {
            return new VictorianSofa();
        } else {
            throw new IllegalArgumentException("未知的沙发类型: " + type);
        }
    }
}

4. 客户端代码

客户端可以通过 FurnitureFactory 提供的静态方法创建产品。

public class FurnitureShop {
    public static void main(String[] args) {
        // 客户希望购买一张现代风格的椅子
        Chair chair = FurnitureFactory.createChair("modern");
        chair.create();

        // 客户希望购买一张维多利亚风格的沙发
        Sofa sofa = FurnitureFactory.createSofa("victorian");
        sofa.create();
    }
}

5.运行结果
创建了一张现代风格的椅子
创建了一张维多利亚风格的沙发

代码分析

  1. 简单工厂类 FurnitureFactory:工厂类提供了两个静态方法 createChaircreateSofa,通过传入的参数决定要创建的具体产品。简单工厂的核心思想就是将对象的创建逻辑集中在一个地方。
  2. 具体产品类:具体产品类如 ModernChairVictorianChair 分别实现了 Chair 接口,提供了具体的产品行为。
  3. 客户端:客户端通过工厂方法调用相应的产品,无需了解产品的具体实现细节。

优缺点

优点:

  • 简化了客户端代码:客户端不需要直接创建对象,只需通过工厂来获取产品。
  • 集中管理产品创建逻辑:所有创建逻辑都集中在一个工厂类中,便于维护和修改。

缺点:

  • 工厂类的职责较重:随着产品类型的增加,工厂类会变得越来越复杂,违反了单一职责原则。
  • 可扩展性差:如果要添加新的产品类型,工厂类需要修改,不符合开闭原则

通过简单工厂模式,我们将所有的创建逻辑集中到了 FurnitureFactory 中,并且通过参数化的方式控制创建不同的产品。这适合于产品种类较少且变化不频繁的情况。

2.2 工厂方法模式

概念:工厂方法模式是一种创建型设计模式,它将对象的创建过程推迟到子类中处理,使得客户端不直接依赖于具体产品类。每个具体工厂都会负责创建一种具体产品,这样就符合开闭原则,并且提供了更好的扩展性。

在上面的家具厂案例中,我们可以通过工厂方法模式来为不同的家具(如椅子和沙发)创建不同的工厂。每个工厂只负责创建一种产品。
在这里插入图片描述

1. 定义产品接口

首先,我们依然保留 ChairSofa 接口,定义它们的 create() 方法。

// 椅子接口
interface Chair {
    void create();
}

// 沙发接口
interface Sofa {
    void create();
}
2. 实现具体产品类

分别实现现代风格和维多利亚风格的椅子和沙发。

// 现代风格的椅子
class ModernChair implements Chair {
    @Override
    public void create() {
        System.out.println("创建了一张现代风格的椅子");
    }
}

// 维多利亚风格的椅子
class VictorianChair implements Chair {
    @Override
    public void create() {
        System.out.println("创建了一张维多利亚风格的椅子");
    }
}

// 现代风格的沙发
class ModernSofa implements Sofa {
    @Override
    public void create() {
        System.out.println("创建了一张现代风格的沙发");
    }
}

// 维多利亚风格的沙发
class VictorianSofa implements Sofa {
    @Override
    public void create() {
        System.out.println("创建了一张维多利亚风格的沙发");
    }
}

3. 创建工厂接口

工厂方法模式的核心思想是,每个具体工厂负责创建一种产品,因此我们需要为每种产品创建不同的工厂接口

// 椅子工厂接口
interface ChairFactory {
    Chair createChair();
}

// 沙发工厂接口
interface SofaFactory {
    Sofa createSofa();
}

4. 实现具体工厂类

我们为现代风格和维多利亚风格的家具分别实现不同的工厂类,每个工厂只负责创建一种风格的产品。

// 现代风格椅子工厂
class ModernChairFactory implements ChairFactory {
    @Override
    public Chair createChair() {
        return new ModernChair();
    }
}

// 维多利亚风格椅子工厂
class VictorianChairFactory implements ChairFactory {
    @Override
    public Chair createChair() {
        return new VictorianChair();
    }
}

// 现代风格沙发工厂
class ModernSofaFactory implements SofaFactory {
    @Override
    public Sofa createSofa() {
        return new ModernSofa();
    }
}

// 维多利亚风格沙发工厂
class VictorianSofaFactory implements SofaFactory {
    @Override
    public Sofa createSofa() {
        return new VictorianSofa();
    }
}

5. 客户端代码

客户端不直接创建产品,而是通过具体工厂创建产品。

public class FurnitureShop {
    public static void main(String[] args) {
        // 客户希望购买一张现代风格的椅子
        ChairFactory chairFactory = new ModernChairFactory();
        Chair chair = chairFactory.createChair();
        chair.create();

        // 客户希望购买一张维多利亚风格的沙发
        SofaFactory sofaFactory = new VictorianSofaFactory();
        Sofa sofa = sofaFactory.createSofa();
        sofa.create();
    }
}

6. 运行结果
创建了一张现代风格的椅子
创建了一张维多利亚风格的沙发

代码分析

  1. 工厂接口 ChairFactorySofaFactory:每个产品(椅子和沙发)有各自的工厂接口,它们定义了创建产品的方法。
  2. 具体工厂类:如 ModernChairFactoryVictorianSofaFactory,这些类实现了相应的工厂接口,并负责创建具体产品。
  3. 客户端:客户端通过具体工厂创建产品,而不直接依赖于产品类。这样可以通过工厂接口动态选择要创建的产品,而无需修改客户端代码。

优缺点

优点:

  • 符合开闭原则:可以轻松扩展新的工厂和产品,而不影响现有代码。
  • 简化客户端代码:客户端只依赖工厂接口,不关心具体的产品类,解耦了对象创建的过程。
  • 更好的扩展性:每增加一种新的产品,只需添加对应的工厂类,不需要修改已有的工厂逻辑。

缺点:

  • 增加了类的数量:每增加一种产品或风格,都需要新建一个工厂类,可能会导致类的数量较多。

通过工厂方法模式,我们将对象的创建过程推迟到了具体工厂中,使得代码更易于扩展,客户端代码也更加简洁。

2.3 抽象工厂模式

概念:抽象工厂模式是一种创建型设计模式,它通过为创建一系列相关或依赖对象提供一个接口,而无需指定它们的具体类。

举个生活中的例子:假设你有一个家具公司,你可以生产两种风格的家具——现代风格和维多利亚风格,每种风格都有沙发、椅子等家具。这时,抽象工厂模式就是一个合适的设计选择。
在这里插入图片描述

1. 创建家具的抽象产品接口
// 椅子接口
interface Chair {
    void create();
}

// 沙发接口
interface Sofa {
    void create();
}
2. 创建具体产品类

分别实现现代风格和维多利亚风格的椅子和沙发。

// 现代风格的椅子
class ModernChair implements Chair {
    @Override
    public void create() {
        System.out.println("创建了一张现代风格的椅子");
    }
}

// 维多利亚风格的椅子
class VictorianChair implements Chair {
    @Override
    public void create() {
        System.out.println("创建了一张维多利亚风格的椅子");
    }
}

// 现代风格的沙发
class ModernSofa implements Sofa {
    @Override
    public void create() {
        System.out.println("创建了一张现代风格的沙发");
    }
}

// 维多利亚风格的沙发
class VictorianSofa implements Sofa {
    @Override
    public void create() {
        System.out.println("创建了一张维多利亚风格的沙发");
    }
}

3.创建抽象工厂类

FurnitureFactory 设计为一个抽象类,定义抽象方法用于创建产品。

// 抽象家具工厂类
abstract class FurnitureFactory {
    public abstract Chair createChair();
    public abstract Sofa createSofa();
}

4. 实现具体的工厂类
// 现代风格家具工厂
class ModernFurnitureFactory extends FurnitureFactory {
    @Override
    public Chair createChair() {
        return new ModernChair();
    }

    @Override
    public Sofa createSofa() {
        return new ModernSofa();
    }
}

// 维多利亚风格家具工厂
class VictorianFurnitureFactory extends FurnitureFactory {
    @Override
    public Chair createChair() {
        return new VictorianChair();
    }

    @Override
    public Sofa createSofa() {
        return new VictorianSofa();
    }
}

5. 客户端代码

客户端依然可以通过工厂类来创建不同风格的家具。

public class FurnitureShop {
    private Chair chair;
    private Sofa sofa;

    public FurnitureShop(FurnitureFactory factory) {
        chair = factory.createChair();
        sofa = factory.createSofa();
    }

    public void showFurniture() {
        chair.create();
        sofa.create();
    }

    public static void main(String[] args) {
        // 客户希望购买一套现代风格的家具
        FurnitureFactory modernFactory = new ModernFurnitureFactory();
        FurnitureShop modernShop = new FurnitureShop(modernFactory);
        modernShop.showFurniture();

        System.out.println("----------------------------");

        // 客户希望购买一套维多利亚风格的家具
        FurnitureFactory victorianFactory = new VictorianFurnitureFactory();
        FurnitureShop victorianShop = new FurnitureShop(victorianFactory);
        victorianShop.showFurniture();
    }
}

6. 运行结果
创建了一张现代风格的椅子
创建了一张现代风格的沙发
----------------------------
创建了一张维多利亚风格的椅子
创建了一张维多利亚风格的沙发

代码分析

  1. 抽象工厂类 FurnitureFactory:我们使用抽象类而不是接口来定义工厂类,并在其中定义了两个抽象方法 createChair()createSofa(),让子类负责具体实现。
  2. 具体工厂类 ModernFurnitureFactoryVictorianFurnitureFactory:每个具体工厂继承了抽象工厂 FurnitureFactory,并实现了创建产品的具体方法。
  3. 客户端代码:客户端使用具体工厂来获取产品实例,通过工厂调用生成椅子和沙发。

优缺点

优点

  • 可以为子类提供部分默认实现(虽然这个例子中没有使用)。如果工厂类有一些通用的功能可以在多个具体工厂中复用,那么抽象类会更加方便。

  • 提供了创建一组相关产品的接口,符合高内聚低耦合原则。

  • 扩展性好,增加新的产品族时只需增加新的工厂和产品类。

缺点:

  • 当需要增加新的产品等级结构时,所有的工厂类都需要修改。
  • Java 的单继承限制仍然存在,如果具体工厂类已经继承了其他类,就无法再继承 FurnitureFactory

3. 三种方式的优缺点对比总结

  • 简单工厂模式

    • 适合简单场景,但不符合开闭原则。
    • 工厂类承担了过多的职责,耦合度较高。
  • 工厂方法模式

    • 符合开闭原则和单一职责原则,适合扩展性强的场景。
    • 需要为每个产品创建相应的工厂,可能造成类爆炸。
  • 抽象工厂模式

    • 适合产品族的扩展,提供高灵活性。
    • 实现复杂,增加新的产品等级时,修改成本较高。

4.SpringBoot中工厂模式实战

项目中有一个登录的需求,有手机号码登录和用户名登录两种方式,这里就可以使用工厂模式进行实现,避免了以往ifelse的弊端,提成高逼格,哈哈

接口和实现:

public interface UserLoginService {

    AuthUser login(LoginBo loginBo);
}

@Service
public class PhoneLoginServiceImpl implements UserLoginService {
    @Override
    public AuthUser login(LoginBo loginBo) {
        System.out.println("phone login");
        AuthUser authUser = new AuthUser();
        authUser.setId("1");
        authUser.setName("zhangsan");
        authUser.setPassword("123456");
        return authUser;
    }

}

@Service
public class UsernameLoginServiceImpl implements UserLoginService {
    @Override
    public AuthUser login(LoginBo loginBo) {
        System.out.println("username login");
        AuthUser authUser = new AuthUser();
        authUser.setId("1");
        authUser.setName("username");
        authUser.setPassword("123456");
        return authUser;
    }

}

工厂类:

@Component
public class LoginFactory implements ApplicationContextAware {

    private Map<String, UserLoginService> LOGIN_TYPE_MAP = new HashMap<>();

    /**
     * 初始化不同登录类型处理类
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        LOGIN_TYPE_MAP.put(AuthConstant.PHONE_MESSAGE_CODE, applicationContext.getBean(PhoneLoginServiceImpl.class));
        LOGIN_TYPE_MAP.put(AuthConstant.USERNAME_PASSWORD, applicationContext.getBean(UsernameLoginServiceImpl.class));
    }

    public UserLoginService getInstance(String loginType) {
        return LOGIN_TYPE_MAP.get(loginType);
    }

}

public class AuthConstant {
    String USERNAME_PASSWORD = "USERNAME_PASSWORD";
    String PHONE_MESSAGE_CODE = "PHONE_MESSAGE_CODE";
}

测试:

@RestController
public class BasicController {

    @Autowired
    private LoginFactory loginFactory;

    @PostMapping("/logintest")
    void login(@RequestBody  LoginBo loginBo){
        UserLoginService userLoginService = loginFactory.getInstance(loginBo.getLoginType());
        userLoginService.login(loginBo);
    }

}

5. 结论

工厂模式在实际开发中非常常见,不同场景下选择合适的模式尤为重要。在需要生成大量复杂对象时,工厂方法模式和抽象工厂模式是非常好的选择;而对于简单的对象生成需求,简单工厂模式足以应对。

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

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

相关文章

Django日志

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) Django 5框…

构建安全畅通的道路网络:EasyCVR视频汇聚平台在道路监控中的创新应用

随着城市化进程的加速和交通流量的不断增加&#xff0c;道路监控已成为确保交通安全、维护社会秩序的重要手段。道路上的监控摄像头多种多样&#xff0c;大致可以分为这几类&#xff1a;交通道路监控、治安监控、路口违章监控&#xff0c;以及车辆测速监控等。基于智慧交通的需…

YoloV8修改分类(Classify)的前处理(记录)

修改原因 yolo自带的分类前处理对于长方形的数据不够友好&#xff0c;存在特征丢失等问题修改后虽然解决了这个问题但是局部特征也会丢失因为会下采样程度多于自带的&#xff0c;总之具体哪种好不同数据应该表现不同我的数据中大量长宽比很大的数据所以尝试修改自带的前处理&a…

怎么做静态码一物一码?批量制作静态码的简单方法

静态二维码是日常很常见的一种二维码类型&#xff0c;一会用来展示文本或者链接跳转等用途使用&#xff0c;比如在很多的物品包装上&#xff0c;扫描二维码就可以查看物品对应的商品编码&#xff0c;就是静态二维码应用的一种。那么静态二维码批量生成的方法是什么样的呢&#…

干货 | Selenium+chrome自动批量下载地理空间数据云影像

1.背景介绍 1.1地理空间数据云 由中国科学院计算机网络信息中心科学数据中心成立的地理空间数据云平台是常见的下载空间数据的平台之一。其提供了较为完善的公开数据&#xff0c;如LANDSAT系列数据&#xff0c;MODIS的标准产品及其合成产品&#xff0c;DEM数据&#xff08;SR…

客户需求挖掘的三个步骤

本文将介绍客户需求挖掘的三个关键步骤&#xff0c;帮助企业更好地理解客户&#xff0c;并提供个性化的服务。通过分析客户需求&#xff0c;可以更好地满足客户期望&#xff0c;提升客户满意度和忠诚度。 前言 本文将介绍客户需求挖掘的三个关键步骤&#xff0c;帮助企业更好地…

ZooKeeper--分布式协调服务

文章目录 ZooKeeperzk的由来zk解决了什么问题 ZK工作原理ZK数据模型zk功能1.命名服务2.状态同步3.配置中心4.集群管理 zk部署单机启动zk验证zk zk集群集群角色选举过程1.节点角色状态2.选举ID3.具体过程4.心跳机制5.ZAB协议 ZooKeeper 选举示例1.第一轮投票&#xff1a;2.节点收…

Flutter学习之一搭建开发环境

Flutter学习之一:搭建ununtu系统开发环境 一.背景 随着企业发展跟环境的变化&#xff0c;目前大前端开发越来越火&#xff0c;在国内应该是一个趋势&#xff1b;个人的技术栈主要还是在原生安卓开发上&#xff1b;长江后浪推前浪&#xff0c;如果不及时学习新知识&#xff0c…

中文文本分类详解及与机器学习算法对比

一.文本分类 文本分类旨在对文本集按照一定的分类体系或标准进行自动分类标记&#xff0c;属于一种基于分类体系的自动分类。文本分类最早可以追溯到上世纪50年代&#xff0c;那时主要通过专家定义规则来进行文本分类&#xff1b;80年代出现了利用知识工程建立的专家系统&…

首届云原生编程挑战赛总决赛冠军比赛攻略_greydog.队

关联比赛: 首届云原生编程挑战赛【复赛】实现一个 Serverless 计算服务调度系统 一、初赛赛道一&#xff08;实现一个分布式统计和过滤的链路追踪&#xff09; 赛题分析 1、数据来源 采集自分布式系统中的多个节点上的调用链数据&#xff0c;每个节点一份数据文件。数据格式…

系统架构师考试学习笔记第四篇——架构设计实践知识(21)安全架构设计理论与实践

本章考点&#xff1a; 第21课时主要学习信息系统中安全架构设计的理论和工作中的实践。根据考试大纲,本课时知识点会涉及案例分析题和论文题(各占25分),而在历年考试中,综合知识选择题目中也有过诸多考查。本课时内容侧重于知识点记忆;,按照以往的出题规律,安全架构设计基础知识…

工具知识 | Linux常用命令

参考 linw7的github《鸟哥的Linux私房菜》 一.文件管理 1.文件查找&#xff1a;find2.文件拷贝&#xff1a;cp3.打包解包&#xff1a;tar 二.文本处理 1.(显示行号)查看文件&#xff1a;nl2.文本查找&#xff1a;grep3.排序&#xff1a;sort4.转换&#xff1a;tr5.切分文本&…

Web 基础——Apache

Event Worker 的升级版、把服务器进程和连接进行分析&#xff0c;基于异步 I/O 模型。 请求过来后进程并不处理请求&#xff0c;而是直接交由其它机制来处理&#xff0c;通过 epoll 机制来通知请求是否完成&#xff1b; 在这个过程中&#xff0c;进程本身一直处于空闲状态&am…

【目标检测数据集】铁轨表面缺损检测数据集4789张VOC+YOLO格式

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4789 标注数量(xml文件个数)&#xff1a;4789 标注数量(txt文件个数)&#xff1a;4789 标注…

只有IP地址没有域名怎么实现HTTPS访问?

&#x1f510; 实现IP地址HTTPS访问 &#x1f310; 确认公网IP地址 公网IP&#xff1a;确保你拥有一个公网IP地址&#xff0c;或者内网映射公网&#xff0c;这是实现HTTPS访问的前提。 &#x1f4dd; 选择证书颁发机构&#xff08;CA&#xff09; 选择CA&#xff1a;选择一个…

【Qt】Qt音频

Qt 音频 在 Qt 中&#xff0c;⾳频主要是通过 QSound 类来实现。但是需要注意的是 QSound 类只⽀持播放 wav 格式的⾳频⽂件。也就是说如果想要添加⾳频效果&#xff0c;那么⾸先需要将 ⾮wav格式 的⾳频⽂件转换为 wav 格式。 【注意】使⽤ QSound 类时&#xff0c;需要添加模…

【C#Mutex】 initiallyOwned错误引起的缺陷

临界区只能对同一个进程的不同线程同步&#xff0c;互斥量可以跨进程同步。典型应用场景&#xff1a;两个exe会操作同一个注册表项。 错误代码 封装类 public class CMutexHelp : IDisposable {public CMutexHelp(){s_mutex.WaitOne();} private static Mutex s_mutex …

深度学习-目标检测(二)Fast R-CNN

一&#xff1a;Fast R-CNN Fast R-CNN 是一篇由Ross Girshick 在 2015 年发表的论文&#xff0c;题为 “Fast R-CNN”。这篇论文旨在解决目标检测领域中的一些问题&#xff0c;特别是传统目标检测方法中存在的速度和准确性之间的矛盾。 论文摘要&#xff1a;本文提出了一种基于…

关于tomcat如何设置自启动的设置

希望文章能给到你启发和灵感&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏 支持一下博主吧&#xff5e; 阅读指南 开篇说明一、基础环境说明1.1 硬件环境1.2 软件环境 二、Windows 下的设置服务自启2.1 服务的注册2.2 开启自启 三、MacOS下设置服务自启…

ROS CDK魔法书:建立你的游戏王国(Python篇)

引言 在虚拟游戏的世界里&#xff0c;数字化的乐趣如同流动的音符&#xff0c;谱写着无数玩家的共同回忆。而在这片充满创意与冒险的乐园中&#xff0c;您的使命就是将独特的游戏体验与丰富的技术知识相结合&#xff0c;打造出令人难以忘怀的作品。当面对如何实现这一宏伟蓝图…