当前位置: 首页 > news >正文

设计模式浅析

一、设计模式的使用场景

设计模式(Design Patterns)是在软件开发中经过验证的最佳实践,用于解决常见的设计问题。它们提供了一种可复用的解决方案,可以帮助开发人员提高代码质量、可维护性和可重用性。设计模式的采用通常在以下情况下被考虑:
1.代码重用性:当您发现多个地方有相似的代码结构或逻辑时,可以考虑使用设计模式来提取这些共通的部分,以提高代码的重用性。
2.扩展性:当系统需要支持未来的扩展或修改时,设计模式可以帮助您构建灵活和可扩展的架构。
3.可维护性:设计模式通常使代码结构更清晰、易于理解,这有助于提高代码的可维护性。通过遵循设计模式的最佳实践,可以使代码更易于阅读、调试和修改。
4.解决复杂问题:当面对复杂的设计问题时,如对象间通信、资源管理、并发控制等,设计模式提供了一种经过验证的解决方案。
5.团队协作:在团队开发环境中,使用设计模式可以提高代码的一致性和可维护性,促进团队成员之间的沟通和协作。
6.适应变化:当软件需求经常发生变化时,设计模式可以帮助您构建更加灵活和适应变化的系统。
需要注意的是,虽然设计模式在软件开发中很有用,但过度使用或不当地使用它们也可能导致代码过度复杂化和难以理解。那怎样定义过度使用呢,遵循事不过三的原则即可,只有没有重复的代码或者方法有三个的时候就不用优化。

二、使用介绍

在之前的工作经历中我有过多次使用设计模式的经历,一次是使用工厂和策略两种设计模式统一接口完成多端多业务类型多类型页面资源,减少了接口数量和开发成本,完成了查询广告页面的组件化,当时面临的问题是有多种类型的app,app上有不同的页面,不同页面根据不同的业务或者标识去数据库里面查询配置的不同的页面,但是我们页面的数据逻辑又在其他系统,我们只能在自己系统内完成这样的筛选逻辑,在当时要么根据不同的客户端开放不同的接口,要么根据不同的业务类型开放不同的接口,那这样肯定会随着端的增多或者业务类型的增多会产生接口爆炸的情况,要么就是在一个接口内完成大量的判断来完成这样的逻辑,那有没有可能借助设计模式来解决呢?当时我就在寻找相关的案例,最后觉得工厂模式和策略模式的结合是很好的方式,简单工厂模式的作用是提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需要知道具体产品类所对应的参数即可。
这样不正是拟合了根据上送和客户端参数创建多端工厂的场景吗?而策略模式是把具体的算法实现从业务逻辑中剥离出来,成为一系列独立算法类,使得它们可以相互替换。那也正好拟合了我们根据上送的业务类型和页面类型寻找不同处理类的场景
*

(一)策略和工厂模式

下面我来展示一个简化版本根据的demo,方便大家理解的。
客户端

@SpringBootTest
public class ApplicationTest {

@Autowired
ClientFactory clientFactory;@Test
public void test() {String result1 = clientFactory.getClient("wechat").getResult();System.out.println("-----------------");System.out.println(result1);String result2 = clientFactory.getClient("alipay").getResult();System.out.println("-----------------");System.out.println(result2);
}

}

创建工厂
@Service
public class ClientFactory {

private final Map<String, ClientService> clientServiceMap = new ConcurrentHashMap<>();public ClientService getClient(String appType) {ClientService clientService = clientServiceMap.get(appType);if (clientService == null) {throw new RuntimeException("未找到客户端");}return clientService;
}

}
客户端接口
public interface ClientService {
String getResult();
}
支付宝实现
@Component(value = “alipay”)
public class AlipayServiceImpl implements ClientService {

@Override
public String getResult() {return "我是支付宝";
}

}
微信实现
@Component(value = “wechat”)
public class WechatServiceImpl implements ClientService {

@Override
public String getResult() {return "我是微信";
}

}

从上面可以看出,调用者仍然只需要传入自己的参数,在寻找具体处理类和方法的路径都被包装在工厂方法和springbean和具体类的映射关系处理中。以后增加了新的客户端百度,只需要新增一个BaiduService处理类即可。

(二)模版方法

还有一次经历是是使用模版方法完成业务逻辑的组件化,之前一个业务逻辑有很多个版本,我还需要再增加2个版本,全部流程大致有15步流程,在不同的版本可能会有缺少不同的步骤,所以之前的逻辑就有在不同步骤中有各自版本的判断导致很难清晰的看出每个版本自己的逻辑是什么,导致我很难加自己的逻辑,也很不利于排查问题。
那怎样解决这样一个问题呢?最后结合模版方法的模式来重构了一遍代码,我们先看下模版方法模式的定义,模板方法模式定义了一个算法
的步骤,并允许子类别为一个或多个步骤提供其实践方式。让子类别在不改变算法架构的情况下,重新定义算法中的某些步骤。它主要优点包括:

  • 封装不变部分:将算法的核心结构和不变部分封装在基本方法中,使得子类可以根据需求对可变部分进行扩展,而不影响不变部分。
  • 代码复用:抽象类中包含的基本方法可以避免子类重复实现相同的代码逻辑,提高了代码的复用性。
  • 更好的扩展性:由于具体实现由子类来完成,可以方便地扩展新的功能或变更实现方式,同时不影响模板方法本身。
    这样的不正好拟合我这样场景吗。我将业务逻辑中的步骤梳理出来,放到一个抽象类中,公共部分在抽象类中实现,不同版本的内容定义成抽象方法,由各个版本的子类完成实现,由传入的参数来和子类形成一个映射关系。这样我增加自己的两个版本,只需要增加两个子类即可,每个版本的逻辑也清晰可见,减少了排查的难度。下面我也来展示一个简化版本根据的demo,方便大家理解的。

客户端
public class Client {
public static void main(String[] args) {
AbstractClass instance1 = new ConcreteClass1();
instance1.templateMethod();

    AbstractClass instance2 = new ConcreteClass2();instance2.templateMethod();
}

}

// 定义抽象类
abstract class AbstractClass {
// 声明为final,避免子类重写模板方法
public final void templateMethod() {
// 调用基本方法
operation1();
abstractMethod1();
operation2();
abstractMethod2();
}
// 基本方法
public void operation1() {
System.out.println(“执行操作1”);
}

public void operation2() {System.out.println("执行操作2");
}// 抽象方法,需要子类实现
public abstract void abstractMethod1();public abstract void abstractMethod2();

}

// 定义具体实现类1
class ConcreteClass1 extends AbstractClass {
@Override
public void abstractMethod1() {
System.out.println(“实现类1,重写抽象方法1”);
}

@Override
public void abstractMethod2() {System.out.println("实现类1,重写抽象方法2");
}

}

// 定义具体实现类2
class ConcreteClass2 extends AbstractClass {
@Override
public void abstractMethod1() {
System.out.println(“实现类2,重写抽象方法1”);
}

@Override
public void abstractMethod2() {System.out.println("实现类2,重写抽象方法2");
}

}

(三)注意事项

以上就是我用设计模式解决的两个工作问题,那么在在工作中,如何有效利用设计模式帮我们解决问题呢?我觉得主要有以下几点:
1.理解业务需求:在开始编码之前,深入了解业务需求是非常重要的。这将帮助我们确定哪些设计模式最适合当前的问题。
2.识别问题:在开发过程中,时刻关注代码中可能出现的重复、冗余或难以维护的部分。这些问题通常是需要应用设计模式的候选者。
3.选择适当的设计模式:根据识别到的问题,拟合设计模式的解决方式,在脑子中模拟改写后的业务代码,大致逻辑通顺后就可以尝试改写了。有的一直设计模式可能还不好解决,那就要先拆解一部分,分批解决,因为工程是有时间、成本要求的,不可能一直等我们苦思冥想和尝试。而且也不要试图一次性将所有代码都改造成使用设计模式。相反,应该逐步改进代码,逐步引入设计模式。这样可以确保代码始终保持在一个稳定且可维护的状态。
4.学习和研究:不断学习新的设计模式,研究它们是如何解决特定问题的。这可以通过阅读书籍、在线教程、博客文章和开源代码库来实现。这样可以让我们脑子里有个设计模式的概念,尽快的能拟合业务场景找到合适的设计模式,这样才保证能在工作中用起来。
5.注意事项:设计模式并不是银弹,我们应该根据具体情况和需求进行选择和调整。不要盲目追求使用设计模式,而是要在理解它们的优缺点的基础上做出决策。
下面我附一下常用设计模式的定义,方便根据定义来映射场景:
设计模式主要分为三类:创建型模式、结构型模式和行为型模式。
1.创建型模式(Creational Patterns)

  • 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。
  • 工厂模式(Factory Pattern):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
  • 抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而不需要指定它们具体的类。
  • 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  • 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
    2.结构型模式(Structural Patterns)
  • 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。
  • 组合模式(Composite Pattern):将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和复合对象的使用具有一致性。
  • 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
  • 外观模式(Facade Pattern):为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
  • 享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象。
    3.行为型模式(Behavioral Patterns)
  • 模板方法模式(Template Method Pattern):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
  • 策略模式(Strategy Pattern):定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式使得算法可独立于使用它的客户。
  • 观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,它的所有依赖者都会自动收到通知并更新。
  • 迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。
  • 责任链模式(Chain of Responsibility Pattern):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
  • 命令模式(Command Pattern):将一个请求封装为一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
  • 备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。以后可将该对象恢复到原先保存的状态。
  • 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
  • 访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各类的结构的情况下定义新的操作。
  • 中介者模式(Mediator Pattern):用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
  • 解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

三、扩展阅读

上述的主要是在代码层面的设计模式,还有一些分类标准有一些设计模式也可以了解下,例如架构模式中的以下设计模式:

  • 分层模式
  • 客户端-服务器模式
  • 主从模式
  • 管道-过滤器模式
  • 代理模式
  • 对等模式
  • 事件总线模式
  • 模型-视图-控制器模式
  • 黑板模式
  • 解释器模式
  • 事件驱动架构
  • 微内核架构
  • 微服务架构
  • 基于空间的架构
    并发编程领域的Thread-Per-Message模式、Future模式、MapReduce模式、任务并行模式、数据并行模式、Reactor模式、Proactor模式、Actor模型、生产者-消费者模式等,并行编程中的设计模式主要是为了解决在并行计算环境中遇到的各种问题和挑战。由于并行编程涉及多个处理器或线程同时执行代码,因此需要特别关注线程间的同步、通信、数据共享和冲突避免等问题。需要注意的是,不同的模式在不同的场景下可能具有不同的优势和适用性,因此需要根据实际情况进行选择。
    相关资料:
    Mark Richards 写的《软件架构:架构模式、特征及实践指南》
    《软件系统架构师教程》
    《Java异步编程实战》
    《微服务设计模式和最佳实践》

相关文章:

设计模式浅析

一、设计模式的使用场景 设计模式&#xff08;Design Patterns&#xff09;是在软件开发中经过验证的最佳实践&#xff0c;用于解决常见的设计问题。它们提供了一种可复用的解决方案&#xff0c;可以帮助开发人员提高代码质量、可维护性和可重用性。设计模式的采用通常在以下情…...

Linux环境中的git

目录 1.要使用git&#xff0c;首先要安装git 2.首次使用git需要做的操作 3.git操作 1.要使用git&#xff0c;首先要安装git 指令&#xff1a;sudo yum install -y git 2.首次使用git需要做的操作 在gitee网页&#xff0c;在你的仓库中找到&#xff1a; 先将下面两行代码分别…...

单测的思路

文章目录 单测的定义方法的单测几种生成工具的对比生成步骤 接口的单测场景的单测总结参考 单测的定义 单元测试&#xff08;Unit Testing&#xff09;是一种软件开发中的测试方法&#xff0c;它的主要目的是确保软件中的最小可测试单元&#xff08;通常是函数、方法或类&…...

Linux内核与驱动面试经典“小”问题集锦(6)

接前一篇文章&#xff1a;Linux内核与驱动面试经典“小”问题集锦&#xff08;5&#xff09; 问题8 问&#xff1a;如何判断一个数是否是2的幂次&#xff08;假设最多32位&#xff09;&#xff1f; 备注&#xff1a;此问题是笔者年前参加小米面试时遇到的一个问题&#xff0c…...

【zabbix】(四)-钉钉告警企业微信配置

前提条件&#xff1a; 已经安装了Python3环境&#xff08;脚本需要requests模块&#xff09;。Centos7.x自带Python2&#xff08;不含requests模块&#xff09; 钉钉告警配置 一 安装Python3 参考该优秀文档部署 查看Python的模块&#xff1a;pip list / pip3 list 报错 …...

python-自动化篇-办公-一键将word中的表格提取到excel文件中

文章目录 代码 工作中&#xff0c;经常需要将Word文档中的表格粘贴到Excel文件中&#xff0c;以便汇总及分析。一个一个复制粘贴&#xff0c;非常不方便&#xff0c;还是Python自动化操作&#xff0c;省心省力。要求如下图所示&#xff0c;即将word中的所有表格&#xff0c;转存…...

C#,数值计算,矩阵的行列式(Determinant)、伴随矩阵(Adjoint)与逆矩阵(Inverse)的算法与源代码

本文发布矩阵&#xff08;Matrix&#xff09;的一些初级算法。 一、矩阵的行列式&#xff08;Determinant&#xff09; 矩阵行列式是指矩阵的全部元素构成的行列式&#xff0c;设A(a)是数域P上的一个n阶矩阵&#xff0c;则所有A(a)中的元素组成的行列式称为矩阵A的行列式&…...

人工智能|推荐系统——基于tensorflow的个性化电影推荐系统实战(有前端)

代码下载&#xff1a; 基于tensorflow的个性化电影推荐系统实战(有前端).zip资源-CSDN文库 项目简介&#xff1a; dl_re_web : Web 项目的文件夹re_sys&#xff1a; Web app model&#xff1a;百度云下载之后&#xff0c;把model放到该文件夹下recommend&#xff1a; 网络模型相…...

Hive SQL编译成MapReduce任务的过程

目录 一、架构及组件介绍 1.1 Hive底层架构 1.2 Hive组件 1.3 Hive与Hadoop交互过程 二、Hive SQL 编译成MR任务的流程 2.1 HQL转换为MR源码整体流程介绍 2.2 程序入口—CliDriver 2.3 HQL编译成MR任务的详细过程—Driver 2.3.1 将HQL语句转换成AST抽象语法树 词法、语…...

【C++】快速上手map、multimap、set、multiset

文章目录 一、前言二、set / multiset1. 常见应用2. 核心操作 三、map / multimap1. 常见应用2. 核心操作 一、前言 S T L STL STL 中的关联式容器分为树型结构和哈希结构&#xff0c;树型结构主要有四种&#xff1a; s e t set set、 m u l t i s e t multiset multiset、 m a…...

【分享】图解ADS+JLINK调试ARM

文章是对LPC2148而写的&#xff0c;但是对三星的44B0芯片同样适用&#xff0c;只需要在选择时将相应的CPU选择的S3C44B0就可以了。 JLINK在ADS下调试心得 前两天一个客户用jlink在ADS下调试LPC2148总报错&#xff0c;这个错误我之前在调试LPC2200的时候也碰到过&#xff0c;后…...

反无人机系统技术分析,无人机反制技术理论基础,无人机技术详解

近年来&#xff0c;经过大疆、parrot、3d robotics等公司不断的努力&#xff0c;具有强大功能的消费级无人机价格不断降低&#xff0c;操作简便性不断提高&#xff0c;无人机正快速地从尖端的军用设备转入大众市场&#xff0c;成为普通民众手中的玩具。 然而&#xff0c;随着消…...

Kotlin和Java 单例模式

Java 和Kotlin的单例模式其实很像&#xff0c;只是Kotlin一部分单例可以用对象类和委托lazy来实现 Java /*** 懒汉式&#xff0c;线程不安全*/ class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (insta…...

软考 系统分析师系列知识点之信息系统战略规划方法(9)

接前一篇文章&#xff1a;软考 系统分析师系列知识点之信息系统战略规划方法&#xff08;8&#xff09; 所属章节&#xff1a; 第7章. 企业信息化战略与实施 第4节. 信息系统战略规划方法 7.4.5 信息工程方法 信息工程&#xff08;Information Engineering&#xff0c;IE&…...

政安晨:示例演绎TensorFlow的官方指南(一){基础知识}

为什么要示例演绎&#xff1f; 既然有了官方指南&#xff0c;咱们在官方指南上看看就可以了&#xff0c;为什么还要写示例演绎的文章呢&#xff1f; 其实对于初步了解TensorFlow的小伙伴们而言&#xff0c;示例演绎才是最重要的。 官方文档已经假定了您已经具备了相当合适的…...

node - 与数据库交互

在Web开发中,与数据库交互是常见的需求,用于持久化存储、检索和操作数据。不同的后端技术和数据库类型(如关系型数据库和非关系型数据库)有着不同的交互方式。下面介绍几种常见的数据库交互方法。 关系型数据库 关系型数据库(如MySQL、PostgreSQL、SQLite)使用结构化查…...

速盾:2024年cdn在5g时代重要吗

在2024年&#xff0c;随着5G技术的普及与应用&#xff0c;内容分发网络&#xff08;Content Delivery Network&#xff0c;CDN&#xff09;在数字化时代中的重要性将进一步巩固和扩大。CDN是一种用于快速、高效地分发网络内容的基础设施&#xff0c;它通过将内容部署在全球各地…...

微信小程序(四十一)wechat-http的使用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.模块下载 2.模块的使用 在终端输入npm install wechat-http 没有安装成功vue的先看之前的一篇 微信小程序&#xff08;二十&#xff09;Vant组件库的配置- 如果按以上的成功配置出现如下报错先输入以下语句 …...

所有设计模式大全及学习链接

文章目录 创建型设计模式结构型设计模式行为型设计模式 创建型设计模式 一种创建对象的设计模式&#xff0c;它们提供了一种灵活的方式来创建对象&#xff0c;同时隐藏了对象的创建细节。以下是常见的创建型设计模式&#xff1a; 工厂方法模式&#xff08;Factory Method Patte…...

【Java程序设计】【C00264】基于Springboot的原创歌曲分享平台(有论文)

基于Springboot的原创歌曲分享平台&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的原创歌曲分享平台 本系统分为平台功能模块、管理员功能模块以及用户功能模块。 平台功能模块&#xff1a;在平台首页可以查看首…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

用递归算法解锁「子集」问题 —— LeetCode 78题解析

文章目录 一、题目介绍二、递归思路详解&#xff1a;从决策树开始理解三、解法一&#xff1a;二叉决策树 DFS四、解法二&#xff1a;组合式回溯写法&#xff08;推荐&#xff09;五、解法对比 递归算法是编程中一种非常强大且常见的思想&#xff0c;它能够优雅地解决很多复杂的…...

拟合问题处理

在机器学习中&#xff0c;核心任务通常围绕模型训练和性能提升展开&#xff0c;但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正&#xff1a; 一、机器学习的核心任务框架 机…...

OpenGL-什么是软OpenGL/软渲染/软光栅?

‌软OpenGL&#xff08;Software OpenGL&#xff09;‌或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式&#xff08;包括几何处理、光栅化、着色等&#xff09;&#xff0c;不依赖GPU硬件加速。这种模式通常性能较低&#xff0c;但兼容性极强&#xff0c;常用于不支持硬件加速…...