探索设计模式的魅力:抽象工厂模式的艺术

个人主页: danci_
🔥系列专栏:《设计模式》《MYSQL应用》
💪🏻 制定明确可量化的目标,坚持默默的做事。
🚀 转载自文章:探索设计模式的魅力:抽象工厂模式的艺术
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,用于在不指定具体类的情况下创建一系列相关或相互依赖的对象。它提供了一个接口,用于创建一系列“家族”或相关依赖对象,而无需指定它们的具体类。
主要参与者:
- 抽象工厂(Abstract Factory):提供一个接口,用于创建一些相关或相互依赖的对象家族,而不需要指定它们具体的类。
- 具体工厂(Concrete Factory):实现抽象工厂的操作以生产具体的产品对象。
- 抽象产品(Abstract Product):为一系列产品对象声明一个接口。
- 具体产品(Concrete Product):抽象产品的子类,定义用于生产的具体产品对象。
- 客户(Client):仅使用由抽象工厂和抽象产品类声明的接口。
实现步骤:
- 定义抽象产品,确定产品家族中的不同产品。
- 创建抽象工厂类,定义创建抽象产品的接口。
- 实现具体工厂类,每个工厂类负责创建不同的产品变体。
- 客户端代码通过抽象工厂和抽象产品类接口与工厂和产品交互。
优势:
- 隔离具体类的生成:客户端不需要知道它所使用的对象的具体类,只需要关心所使用对象的接口。
- 易于交换产品系列:因为具体的工厂类都派生自同一个抽象类,可以很容易地更换使用的工厂类来切换整个产品系列。
- 增强一致性:产品在一系列中一致地创建,这保证了客户端始终只使用同一产品系列中的对象。
缺点:
- 难以支持新种类的产品:如果需要添加额外的产品到系列中,抽象工厂和所有具体工厂类都需要改变,这违反了开闭原则。
探索设计模式的魅力:简单工厂模式-CSDN博客文章浏览阅读2.5k次,点赞58次,收藏46次。实现简单工厂的难点就在于 “如何选择” 实现,前面便子中传递参数的方法, 那都是静态的参数,还可以实现成为动态的参数。客户端通过简单工厂创建 了一个实现接口的对象,然后面向接口编程,从客户端来看,它根本不知道具体的实现是什么,也不知道是如何实现的,它只知道通过工厂获得了一个接口对象 , 然后通过这个接口来获取想要的功能。如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。https://blog.csdn.net/danci_/article/details/135566105探索设计模式的魅力:工厂方法模式-CSDN博客文章浏览阅读2.5k次,点赞83次,收藏47次。工厂方法模式是一种创建型设计模式,它提供了一种创建对象的接口,但将具体实例化对象的工作推迟到子类中完成。这样做的目的是创建对象时不用依赖于具体的类,而是依赖于抽象,这提高了系统的灵活性和可扩展性。优点:降低耦合度、增加了系统的可扩展性 和 提高代码的可维护性;缺点:增加了代码的复杂性 和 需要更多的设计考虑。https://blog.csdn.net/danci_/article/details/135611783
目录
一、案例
1.1 示例代码
1.1.1 简单工厂实现
1.1.2 问题
1.1.3 抽象工厂实现
二、模式讲解
2.1 功能
2.2 抽象工厂模式的结构及说明
2.3 示例代码程序结构图
2.4 抽象工厂模式与简单工厂模式
2.5 抽象工厂模式与工厂方法模式
一、案例
场景:造一辆汽车(买零件来组装),汽车有很多的零组成,成百上千个零件相互依赖配合工作,比如发动机和变速箱。
选择零件时,每个零件的品牌、规格 等如何才能选择到合适的搭配才能配合正常工作,也就是说汽车是一个整体,每个零件之间有关联的。
1.1 示例代码
汽车零件有成百上升个,这里只举例发动机和变速箱。市面上有各种品牌的发动机和变速箱,同一品牌还有各种型等,这里举两个。
1.1.1 简单工厂实现
发动机接口:
public interface EngineApi {void run();
}
变速箱接口:
public interface GearboxApi {void run();
}
林肯发动机和林肯变速箱:
public class LinkenEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("林肯发动机工作了");}
}public class LinkenGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("林肯变速箱工作了");}
}
丰田发动机和丰田变速箱:
public class ToyotaEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("丰田发动机工作了");}
}public class ToyotaGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("丰田变速箱工作了");}
}
发动机工厂:
public class EngineFactory {public static EngineApi getEngineApi(int i) {if (i == 1) {return new LinkenEngineApiImpl();}return new ToyotaEngineApiImpl();}
}
变速箱工厂 :
public class GearboxFactory {public static GearboxApi getGearbox(int i) {if (1 == i) {return new LinkenGearboxApiImpl();}return new ToyotaGearboxApiImpl();}
}
汽车组装类:
public class CarEngineer {public void makeCar(int engineType, int gearboxType) {EngineApi engineApi = EngineFactory.getEngineApi(engineType);GearboxApi gearbox = GearboxFactory.getGearbox(gearboxType);engineApi.run();gearbox.run();}
}
客户端:
public class CarClient {public static void main(String[] args) {CarEngineer carEngineer = new CarEngineer();carEngineer.makeCar(1, 1);}
}
运行结果:
/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
林肯发动机工作了
林肯变速箱工作了
修改客户端carEngineer.makeCar(1, 2); 运行结果:
/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
林肯发动机工作了
丰田变速箱工作了
1.1.2 问题
修改了产数之后,组装的汽车使用了林肯的发动机,而变速箱是丰田的,此时发动机与变速箱不是一个品牌,如果发动机与变速箱不匹配无法正常配合工作,那么组装的这个汽车就等于废了(这里假设只有同品牌的零部件才能正常配合动作)。
显然发动机与变速箱是需要互相匹配,强依赖关系。就是选了这个发动机就必须选定某个变速箱。抽象工厂来解决这个问题。
1.1.3 抽象工厂实现
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接又,而无需指定它们具体的类。
解决1.1.2问题是要创建一序列有相互依赖关联和相互约束的产品——抽象工厂模式。
代码改造:
发动机接口和变速箱接口不变:
public interface EngineApi {void run();
}
public interface GearboxApi {void run();
}
发动机和变速箱的实现也不变:
public class LinkenEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("林肯发动机工作了");}
}public class LinkenGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("林肯变速箱工作了");}
}public class ToyotaEngineApiImpl implements EngineApi {@Overridepublic void run() {System.out.println("丰田发动机工作了");}
}public class ToyotaGearboxApiImpl implements GearboxApi {@Overridepublic void run() {System.out.println("丰田变速箱工作了");}
}
添加抽象工厂:(工厂抽象出来)
public interface AbstractFactory {/*** 创建发动机 <br/>*/EngineApi createLinken();/*** 创建变速箱 <br/>*/GearboxApi createGearbox();
}
发动机工厂修改为林肯工厂,并实现抽象工厂:(//注释部分为简单工厂代码)
public class LinkenFactory implements AbstractFactory {
//public class EngineFactory {/*** 生产林肯发动机*/@Overridepublic EngineApi createLinken() {return new LinkenEngineApiImpl();}/*** 生产林肯发变速箱*/@Overridepublic GearboxApi createGearbox() {return new LinkenGearboxApiImpl();}//public static EngineApi getEngineApi(int i) {// if (i == 1) {// return new LinkenEngineApiImpl();// }//// return new ToyotaEngineApiImpl();//}
}
变速箱工厂修改为丰田工厂,并实现抽象工厂:(//注释部分为简单工厂代码)
public class ToyotaFactory implements AbstractFactory {
//public class GearboxFactory {/*** 生产丰田发动机*/@Overridepublic EngineApi createLinken() {return new ToyotaEngineApiImpl();}/*** 生产丰田变事箱*/@Overridepublic GearboxApi createGearbox() {return new ToyotaGearboxApiImpl();}//public static GearboxApi getGearbox(int i) {// if (1 == i) {// return new LinkenGearboxApiImpl();// }//// return new ToyotaGearboxApiImpl();//}
}
汽车组装类有修改:(//注释部分为简单工厂代码)
public class CarEngineer {/*** 接收选择好的哪一个序列产品工厂* @param factory*/public void makeCar(AbstractFactory factory) {EngineApi engineApi = factory.createLinken();GearboxApi gearbox = factory.createGearbox();engineApi.run();gearbox.run();}//public void makeCar(int engineType, int gearboxType) {// EngineApi engineApi = EngineFactory.getEngineApi(engineType);// GearboxApi gearbox = GearboxFactory.getGearbox(gearboxType);// engineApi.run();// gearbox.run();//}
}
客户端:(//注释部分为简单工厂代码)
public class CarClient {public static void main(String[] args) {//CarEngineer carEngineer = new CarEngineer();//carEngineer.makeCar(1, 2);CarEngineer carEngineer = new CarEngineer();// 传入选中的哪种产品工厂carEngineer.makeCar(new LinkenFactory());}
}
运行结果:
/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
林肯发动机工作了
林肯变速箱工作了
修改选中的产品工厂carEngineer.makeCar(new ToyotaFactory()) ,运行结果:
/Library/Java/JavaVirtualMachines/jdk1.8.0_311.jdk/...
丰田发动机工作了
丰田变速箱工作了
这个抽象工厂相当于选择一套方案,方案确定好,里面的零件也就确定好了。不用一个零件一个零件的选择以免选择出错。
二、模式讲解
2.1 功能
功能: 为一系列相关对象或相互依赖的对象创建一个接口。
接口内的方法是一系列相互依赖和约束的方法。
2.2 抽象工厂模式的结构及说明

AbstractFactory:抽象工厂,定义创建一系列产品对象的操作接口。
FactoryA:具体的工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建。
AbstractProduct:定义类产品对象的接口。
ProductA:具体的产品实现对象,通常在具体工厂里面,会选择具体的产品实现对象,来创建符合抽象工厂定义的方法返回的产品类型的对象。
Client:客户端,主要使用抽象工厂来获取一系列所需要的产品对象,然后面向这些产品对象的接口编程,以实现需要的功能。
2.3 示例代码程序结构图

抽象工厂模式主要用于以下几个方面的应用场景中:
需要创建一系列相互依赖的对象:当一组对象之间存在依赖关系,并且需要保证这些对象是兼容的,抽象工厂模式可以用来创建这些对象的族群。
希望实现多个产品族的变化:抽象工厂模式允许你定义多个工厂类,每个工厂类可以创建不同的产品族,从而可以实现对产品族的变化。
需要切换产品组合:通过使用抽象工厂模式,可以很方便地切换不同的产品组合,而无需修改已有的客户端代码。
优势方面,抽象工厂模式具有以下几个优势:
封装了对象的创建过程:客户端只需关注抽象工厂类和抽象产品类,而无需关心具体的创建细节,将对象创建的过程封装在工厂类中,提供了更高的封装性和抽象性。
符合开闭原则:抽象工厂模式对于新增新的产品族非常方便,只需创建对应的新的工厂类即可,并且不需要修改已有的代码,符合开闭原则。
保持产品族的一致性:通过抽象工厂模式创建的产品族中的产品具有一定的约束关系,保证了产品的一致性,避免了不兼容的产品组合。
2.4 抽象工厂模式与简单工厂模式
抽象工厂模式和简单工厂模式是两种常见的设计模式,它们在对象的创建和管理上有一些不同之处。
1. 目的和应用场景:
- 简单工厂模式(Simple Factory Pattern)旨在根据给定的参数来创建单一类型的对象实例。它适用于需要根据条件创建不同类型的对象的情况,但它并没有分离对象的创建和使用,违反了单一职责原则。
- 抽象工厂模式(Abstract Factory Pattern)旨在创建一系列相关或相互依赖的对象,而无需显式指定其具体类。它适用于需要创建一组相关的产品对象,并且需要确保这些产品是兼容的情况。
2. 结构与实现:
- 简单工厂模式通常由一个工厂类通过静态方法来创建对象,客户端通过调用工厂类的方法并传入相应的参数来获得所需的对象。
- 抽象工厂模式通常由一组抽象工厂和一组具体工厂类组成,每个具体工厂负责创建一组特定的产品。
3. 灵活性与扩展性:
- 简单工厂模式的灵活性相对较低,因为一旦需要添加新类型的产品,通常需要修改工厂类的静态方法。
- 抽象工厂模式支持产品族的概念,可以非常容易地添加新的产品族,只需要新增对应的具体工厂类即可,而不需要修改客户端代码。
总的来说,简单工厂模式适用于需要创建单一类型的对象,并且可以根据条件动态地创建不同类型的对象。而抽象工厂模式适用于创建一系列相关或相互依赖的对象,并且需要确保这些对象是兼容的情况。在实际应用中,根据具体的需求和设计目标来选择合适的设计模式。
2.5 抽象工厂模式与工厂方法模式
抽象工厂模式(Abstract Factory Pattern)和工厂方法模式(Factory Method Pattern)虽然同属于创建型设计模式,旨在解耦对象的创建和使用,但两者在目的、实现方式及应用场景上存在明显区别:
1. 目的:
- 工厂方法模式的目的是允许一个类在不知道将要创建的对象的具体类型的情况下,推迟其实例化到子类中进行。
- 抽象工厂模式的目的是创建一系列相关或者相互依赖的对象,而不需要指定它们具体的类。
2. 实现方式:
- 工厂方法模式定义了一个用于创建对象的接口,但由子类决定实例化哪一个类。工厂方法让类的实例化推迟到子类中进行。
- 抽象工厂模式提供了一个创建一系列相关或互相依赖对象的接口,而不需要指定它们具体的类。它通常包含多个工厂方法来创建一系列不同的产品。
3. 应用场景:
- 工厂方法模式主要用于单一产品的创建情形,即客户端只需要一个产品,而具体哪个产品则由具体工厂类在运行时决定。
- 抽象工厂模式适用于创建一组产品(产品族),这些产品设计成合作使用的,客户端需要多个产品对象,这些对象要按照一定的方式配合工作。
4. 结构复杂度:
- 工厂方法模式结构相对简单,每个具体工厂类只需要负责一个产品的创建。
- 抽象工厂模式结构相对复杂,一个工厂类需要负责多个产品对象的创建,这些对象通常属于不同的类系列。
5. 扩展难度:
- 工厂方法模式较容易扩展,引入新的产品类型只需要添加相应的具体工厂类和产品类即可。
- 抽象工厂模式相对难以扩展,如果需要添加新的产品系列,需修改抽象工厂的接口以及所有的实现类,这会违反开闭原则。
总之,工厂方法模式用于创建一个产品,而抽象工厂模式用于创建多个相互依赖或相互关联的产品族。在选择使用哪一个模式时,需要根据具体场景和设计需求去判断。
相关文章:
探索设计模式的魅力:抽象工厂模式的艺术
个人主页: danci_ 🔥系列专栏:《设计模式》《MYSQL应用》 💪🏻 制定明确可量化的目标,坚持默默的做事。 🚀 转载自文章:探索设计模式的魅力:抽象工厂模式的艺术 抽象工厂模式&…...
果园系统养殖游戏喂养偷菜种植浇水养成小程序
装扮 通过购买装扮场景切换不同的农场风格 土地升级 通过特定的材料对土地和房屋进行升级 日志 记录道具的使用数量及金币农作物的收入情况 幸运转盘 可用金币进行抽奖 宝箱开启 获得宝箱后可以通过金币开启 每日签到 每日签到获得奖励 系统公告 可以第一时间知道游戏的更新和…...
Windows版PHP7.4.9解压直用(免安装-绿色-项目打包直接使用)
安装版和解压版 区别 安装版: 安装方便,下一步------下一步就OK了,但重装系统更换环境又要重新来一遍,会特别麻烦解压版(推荐): 这种方式(项目打包特别方便)能更深了解mysql的配置&…...
凡泰极客亮相2024 亚马逊云科技出海全球化论坛,为企业数字化出海赋能
随着「不出海,即出局」登上热搜榜单,企业出海已成燎原之势,3月29日,2024 亚马逊云科技出海全球化论坛在深圳成功举办,凡泰极客创始人梁启鸿受邀出席,并以 「App 2.0:以SuperApp构建智能数字生态…...
新零售门店、商品、会员管理指标体系总览
新零售,旨在打破传统零售业的边界,引入先进科技和数字化手段,通过整合线上线下渠道,全面提升用户体验,并实现更智能、高效、个性化的零售运营模式。这一模式不仅仅关注销售产品,更注重构建全方位的购物生态…...
网上订餐系统|基于springboot的网上订餐系统设计与实现(源码+数据库+文档)
网上订餐系统目录 目录 基于springboot的网上订餐系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户功能模块的实现 (1)用户注册界面 (2)用户登录界面 (3)菜品详情界面 (…...
python的抽象类和抽象方法
抽象类是一种不能直接被继承的类。举个例子,我们可以从类Creature衍生出类People,Cats,其中前者两条腿走路,后者四条腿走路,而单独的类Creature却没有一个几条腿走路的方法,因为这是不确定的。 ࿰…...
Android MVVM架构学习——ViewModel DataBinding
关于MVVM架构,我并不想花篇幅去做重复性的描述,网上一搜都是一堆讲解,大家可以自行了解,我所做的只是以最简单的例子,最有效的步骤,从零开始,去实现一个相对有点学习参考价值的项目。 先来看本…...
防抖与节流
...
理解 Nginx 的多站点配置:为每个网站单独配置
Nginx 是一个高性能的 Web 服务器,广泛用于托管和管理网站。它之所以受欢迎,部分原因在于它的灵活性和强大的配置能力。特别是对于管理多个网站,Nginx 提供了一种高效且组织良好的方法。让我们逐步了解如何使用 Nginx 配置多个网站࿰…...
支持向量机模型pytorch
通过5个条件判定一件事情是否会发生,5个条件对这件事情是否发生的影响力不同,计算每个条件对这件事情发生的影响力多大,写一个支持向量机模型pytorch程序,最后打印5个条件分别的影响力。 示例一 支持向量机(SVM)是一种…...
轮转数组(力扣)
189. 轮转数组 - 力扣(LeetCode) 189. 轮转数组 题解 给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 样例输入 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮…...
批量插入10w数据方法对比
环境准备(mysql5.7) CREATE TABLE user (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 唯一id,user_id bigint(10) DEFAULT NULL COMMENT 用户id-uuid,user_name varchar(100) NOT NULL COMMENT 用户名,user_age bigint(10) DEFAULT NULL COMMENT 用户年龄,create_time time…...
HAL STM32 I2C方式读取MT6701磁编码器获取角度例程
HAL STM32 I2C方式读取MT6701磁编码器获取角度例程 📍相关篇《Arduino通过I2C驱动MT6701磁编码器并读取角度数据》🎈《STM32 软件I2C方式读取MT6701磁编码器获取角度例程》📌MT6701当前最新文档资料:https://www.magntek.com.cn/u…...
如何排查nginx服务启动情况,杀死端口,以及防火墙开放指定端口【linux与nginx排查手册】
利用NGINX搭建了视频服务,突然发现启动不了了,于是命令开始 使用以下命令查看更详细的错误信息: systemctl status nginx.service Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk. Run…...
用Rust实现免费调用ChatGPT的命令行工具 (一)
代码已经开源:🚀 fgpt 欢迎大家star⭐和fork 👏 ChatGPT现在免费提供了GPT3.5的Web访问,不需要注册就可以直接使用,但是,它的使用方式是通过Web页面,不够方便。 更多技术分享关注 入职啦&…...
mysql 查询实战1-题目
学习了mysql 查询实战-变量方式-解答-CSDN博客,接着练习sql,从实战中多练习。 1,题目: 1,查询部门工资最高的员工 1,建表: DROP TABLE IF EXISTS department; create table department(dept_i…...
Word学习笔记之奇偶页的页眉与页码设置
1. 常用格式 在毕业论文中,往往有一下要求: 奇数页右下角显示、偶数页左下角显示奇数页眉为每章标题、偶数页眉为论文标题 2. 问题解决 2.1 前期准备 首先,不论时要求 1、还是要求 2,这里我们都要做一下设置: 鼠…...
数据赋能(58)——要求:数据赋能实施部门能力
“要求:数据赋能实施部门能力”是作为标准的参考内容编写的。 在实施数据赋能中,数据赋能实施部门的能力体现在多个方面,关键能力如下图所示。 在实施数据赋能的过程中,数据赋能实施部门应具备的关键能力如下。 理性思维与逻辑分…...
Unity URP PBR_Cook-Torrance模型
Cook-Torrance模型是一个微表面光照模型,认为物体的表面可以看作是由许多个理想的镜面反射体微小平面组成的。 单点反射镜面反射漫反射占比*漫反射 漫反射 基础色/Π 镜面反射DFG/4(NV)(NL) D代表微平面分布函数,描述的是法线与半角向量normalize(L…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
