Java设计模式_单例模式
Java设计模式_单例模式
亦称: 单件模式、Singleton
意图
单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-asf8w5DU-1678452651957)(./assets/singleton.png)]
问题
单例模式同时解决了两个问题, 所以违反了单一职责原则:
-
保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例数量? 最常见的原因是控制某些共享资源 (例如数据库或文件) 的访问权限。
它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的对象, 而不是一个新对象。
注意, 普通构造函数无法实现上述行为, 因为构造函数的设计决定了它必须总是返回一个新对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T2l1OPib-1678452651960)(./assets/singleton-comic-1-zh.png)]
客户端甚至可能没有意识到它们一直都在使用同一个对象。
-
为该实例提供一个全局访问节点。 还记得你 (好吧, 其实是我自己) 用过的那些存储重要对象的全局变量吗? 它们在使用上十分方便, 但同时也非常不安全, 因为任何代码都有可能覆盖掉那些变量的内容, 从而引发程序崩溃。
和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码覆盖。
还有一点: 你不会希望解决同一个问题的代码分散在程序各处的。 因此更好的方式是将其放在同一个类中, 特别是当其他代码已经依赖这个类时更应该如此。
如今, 单例模式已经变得非常流行, 以至于人们会将只解决上文描述中任意一个问题的东西称为单例。
解决方案
所有单例的实现都包含以下两个相同的步骤:
- 将默认构造函数设为私有, 防止其他对象使用单例类的
new
运算符。 - 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。
如果你的代码能够访问单例类, 那它就能调用单例类的静态方法。 无论何时调用该方法, 它总是会返回相同的对象。
真实世界类比
政府是单例模式的一个很好的示例。 一个国家只有一个官方政府。 不管组成政府的每个人的身份是什么, “某政府” 这一称谓总是鉴别那些掌权者的全局访问节点。
单例模式结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p3PHaEzf-1678452651960)(./assets/structure-zh.png)]
单例 (Singleton) 类声明了一个名为
getInstance
获取实例的静态方法来返回其所属类的一个相同实例。单例的构造函数必须对客户端 (Client) 代码隐藏。 调用
获取实例
方法必须是获取单例对象的唯一方式。
伪代码
在本例中, 数据库连接类即是一个单例。 该类不提供公有构造函数, 因此获取该对象的唯一方式是调用 获取实例
方法。 该方法将缓存首次生成的对象, 并为所有后续调用返回该对象。
// 数据库类会对`getInstance(获取实例)`方法进行定义以让客户端在程序各处
// 都能访问相同的数据库连接实例。
class Database is// 保存单例实例的成员变量必须被声明为静态类型。private static field instance: Database// 单例的构造函数必须永远是私有类型,以防止使用`new`运算符直接调用构// 造方法。private constructor Database() is// 部分初始化代码(例如到数据库服务器的实际连接)。// ……// 用于控制对单例实例的访问权限的静态方法。public static method getInstance() isif (Database.instance == null) thenacquireThreadLock() and then// 确保在该线程等待解锁时,其他线程没有初始化该实例。if (Database.instance == null) thenDatabase.instance = new Database()return Database.instance// 最后,任何单例都必须定义一些可在其实例上执行的业务逻辑。public method query(sql) is// 比如应用的所有数据库查询请求都需要通过该方法进行。因此,你可以// 在这里添加限流或缓冲逻辑。// ……class Application ismethod main() isDatabase foo = Database.getInstance()foo.query("SELECT ……")// ……Database bar = Database.getInstance()bar.query("SELECT ……")// 变量 `bar` 和 `foo` 中将包含同一个对象。
单例模式适合应用场景
如果程序中的某个类对于所有客户端只有一个可用的实例, 可以使用单例模式。
单例模式禁止通过除特殊构建方法以外的任何方式来创建自身类的对象。 该方法可以创建一个新对象, 但如果该对象已经被创建, 则返回已有的对象。
如果你需要更加严格地控制全局变量, 可以使用单例模式。
单例模式与全局变量不同, 它保证类只存在一个实例。 除了单例类自己以外, 无法通过任何方式替换缓存的实例。
请注意, 你可以随时调整限制并设定生成单例实例的数量, 只需修改 获取实例
方法, 即 getInstance 中的代码即可实现。
实现方式
- 在类中添加一个私有静态成员变量用于保存单例实例。
- 声明一个公有静态构建方法用于获取单例实例。
- 在静态方法中实现"延迟初始化"。 该方法会在首次被调用时创建一个新对象, 并将其存储在静态成员变量中。 此后该方法每次被调用时都返回该实例。
- 将类的构造函数设为私有。 类的静态方法仍能调用构造函数, 但是其他对象不能调用。
- 检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用。
单例模式优缺点
-
你可以保证一个类只有一个实例。
-
你获得了一个指向该实例的全局访问节点。
-
仅在首次请求单例对象时对其进行初始化。
-
违反了单一职责原则。 该模式同时解决了两个问题。
-
单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。
-
该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
-
单例的客户端代码单元测试可能会比较困难, 因为许多测试框架以基于继承的方式创建模拟对象。 由于单例类的构造函数是私有的, 而且绝大部分语言无法重写静态方法, 所以你需要想出仔细考虑模拟单例的方法。 要么干脆不编写测试代码, 或者不使用单例模式。
与其他模式的关系
- 外观模式类通常可以转换为单例模式类, 因为在大部分情况下一个外观对象就足够了。
- 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元模式就和单例类似了。 但这两个模式有两个根本性的不同。
- 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
- 单例对象可以是可变的。 享元对象是不可变的。
- 抽象工厂模式、 生成器模式和原型模式都可以用单例来实现。
AI代码示例
单例模式是一种创建型设计模式,用于保证一个类仅有一个实例,并提供全局访问点。
在实现单例模式时,需要确保一个类仅有一个实例,并提供一个全局的访问点,以便其他对象可以通过该访问点获取该实例。单例模式通常适用于需要对资源进行集中管理的情况,如数据库连接、线程池等。
在 Java 中,实现单例模式有多种方法,包括懒汉式、饿汉式、双重校验锁等。具体实现方式可以根据实际情况选择。
懒汉式单例模
csharpCopy codepublic class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
在上面的实现中,Singleton
类的构造方法被声明为私有,这意味着只有在Singleton
类内部才能实例化它。
Singleton
类中有一个私有的静态成员变量instance
,用于存储Singleton
类的唯一实例。
getInstance()
方法是公共的静态方法,用于获取Singleton
类的唯一实例。在第一次调用该方法时,instance
被初始化为一个新的Singleton
对象,以后每次调用该方法时,都会返回同一个instance
对象。
这种懒汉式单例模式的实现方式具有懒加载的特点,即只有在第一次使用时才会创建对象。它的缺点是,在多线程环境下可能会出现线程安全问题,因此需要在getInstance()
方法中添加同步锁来解决这个问题。
饿汉式单例模式
除了懒汉式单例模式,还有另一种实现单例模式的方式,称为饿汉式单例模式。在饿汉式单例模式中,类的实例在类加载时就已经被创建,因此不存在线程安全问题。
public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
在这个实现中,instance
成员变量被声明为私有的静态成员变量,并且在类加载时就被初始化为一个新的Singleton
对象。getInstance()
方法简单地返回instance
对象即可。
饿汉式单例模式的缺点是,它无法实现懒加载,即使在应用程序中没有使用该对象,它也会被创建,可能会浪费一定的内存空间。
双重校验锁单例模式
双重校验锁单例模式(Double-Checked Locking Singleton Pattern)是一种高效的单例模式实现方式。在这种方式中,首先检查是否已经存在一个实例,如果不存在才进行同步,这样一来,只有第一次会同步,之后的获取实例操作就不会进行同步了,从而减少了程序的开销。
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
在这个示例代码中,volatile
关键字用于确保 instance
变量在多个线程之间的可见性,synchronized
关键字用于在多线程环境下保证线程安全。
枚举单例模式
枚举单例模式是一种实现单例模式的方式,相较于其他方式,它具有简单、安全、线程安全等优点。在Java 5之后,枚举单例模式成为了官方推荐的实现单例模式的方式之一。
public enum Singleton {INSTANCE;public void doSomething() {// 执行相关操作}
}
在这种实现方式中,Singleton是一个枚举类型,它只有一个枚举常量INSTANCE。因为枚举类型是线程安全的,并且在Java中保证只会有一个枚举常量,所以通过枚举类型实现的单例模式也是线程安全的。
在使用时,只需要调用Singleton.INSTANCE即可获取单例对象。例如:
Singleton singleton = Singleton.INSTANCE;
singleton.doSomething();
枚举单例模式的优点包括:
- 线程安全:枚举类型保证了线程安全,任何时候都只会有一个实例存在。
- 简单:枚举类型的实现方式相对于其他单例模式的实现方式,代码更加简单易懂。
- 反序列化安全:由于枚举类型的实例是在枚举类型被加载时创建的,所以它们不会被反序列化多次,从而保证了反序列化的安全性。
需要注意的是,枚举单例模式虽然具有很多优点,但是它并不适用于所有的场景。例如,如果需要延迟加载单例对象,就不能使用枚举单例模式。在这种情况下,需要使用其他的单例模式实现方式,比如双重校验锁单例模式。
玄子代码示例
饿汉式
package CH_12.Singleton.Hungry;public class GirlFriend {public static int a = 1;// 在内部创建私有对象,使用 static 修饰,在类加载时就创建对象// 不管是否使用都提前创建了,饿汉private static GirlFriend girlFriend = new GirlFriend("小红");private String name;private GirlFriend(String name) {System.out.println("构造器被使用");// 检验构造器是否被创建this.name = name;}// 将构造器私有化,不允许外部创建对象public static GirlFriend getInstance() {return girlFriend;}// 再使用公共的 getInstance() 方法返回 GirlFriend 对象@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\'' +'}';}
}
package CH_12.Singleton.Hungry;public class HungryMan {public static void main(String[] args) {System.out.println(GirlFriend.a);// 调用属性,对象就加载,造成资源浪费GirlFriend instance = GirlFriend.getInstance();System.out.println(instance);// 对象一GirlFriend instance2 = GirlFriend.getInstance();System.out.println(instance2);// 对象2System.out.println(instance == instance2);// 内存地址一致}
}
懒汉式
package CH_12.Singleton.Lazy;public class GirlFriend {public static int a = 1;// 在内部创建私有对象,使用 static 修饰,在类加载时就创建对象// 不管是否使用都提前创建了,饿汉private static GirlFriend girlFriend;private String name;private GirlFriend(String name) {System.out.println("创建成功");// 检验构造器是否被创建this.name = name;}// 将构造器私有化,不允许外部创建对象public static GirlFriend getInstance() {if (girlFriend == null) {girlFriend = new GirlFriend("小红");}// 如果对象为空才创建,二次调用就返回上次创建的对象// 但是存在线程安全的问题,可同时创建多个对象return girlFriend;}// 再使用公共的 getInstance() 方法返回 GirlFriend 对象@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\'' +'}';}
}
package CH_12.Singleton.Lazy;public class Lazyman {public static void main(String[] args) {System.out.println(GirlFriend.a);
// 调用属性,对象就加载,造成资源浪费GirlFriend instance = GirlFriend.getInstance();System.out.println(instance);// 对象一GirlFriend instance2 = GirlFriend.getInstance();System.out.println(instance2);// 对象2System.out.println(instance == instance2);// 内存地址一致//}
}
双重校验锁
package CH_12.Singleton.DoubleLock;public class GirlFriend {public static int a = 1;// 在内部创建私有对象,使用 static 修饰,在类加载时就创建对象// 不管是否使用都提前创建了,饿汉private static GirlFriend girlFriend;private String name;private GirlFriend(String name) {System.out.println(Thread.currentThread().getName() + "-----OK");// 检验构造器是否被创建this.name = name;}// 将构造器私有化,不允许外部创建对象public static GirlFriend getInstance() {if (girlFriend == null) {// 双重校验锁 DCL 懒汉式synchronized (GirlFriend.class) {if (girlFriend == null) {girlFriend = new GirlFriend("小红");}}}// 如果对象为空才创建,二次调用就返回上次创建的对象// 但是存在线程安全的问题,可同时创建多个对象return girlFriend;}// 再使用公共的 getInstance() 方法返回 GirlFriend 对象@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\'' +'}';}
}
package CH_12.Singleton.DoubleLock;public class Lazyman {public static void main(String[] args) {
// System.out.println(GirlFriend.a);
调用属性,对象就加载,造成资源浪费
// GirlFriend instance = GirlFriend.getInstance();
// System.out.println(instance);
// // 对象一
// GirlFriend instance2 = GirlFriend.getInstance();
// System.out.println(instance2);
// // 对象2
// System.out.println(instance == instance2);
// // 内存地址一致
//
// // Runtimefor (int i = 0; i < 10; i++) {new Thread(() -> {GirlFriend.getInstance();}).start();}}
}
Java设计模式_单例模式-玄子3.7
相关文章:

Java设计模式_单例模式
Java设计模式_单例模式 亦称: 单件模式、Singleton 意图 单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a…...

刚刚学完CSS :display float,flex flow 傻傻分不清了
目录 描述 示例: CSS 中的 display CSS 中的 float CSS 中的 flex 描述 刚刚学完CSS ,导致浮动(float),弹性布局(display:flex)好几个字段配置属性已经分不清了。 display float 就同层级别…...

python建立图片索引数据库,根据一段文字,找到存放在电脑上最匹配的图片
python建立图片索引数据库,根据一段文字,找到存放在电脑上最匹配的图片 作者:虚坏叔叔 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 一、程序的用处 一键视频 可以根据一…...

MySQL OCP888题解048-letter N in slow query log(慢查询日志里的字母N)
文章目录1、原题1.1、英文原题1.2、中文翻译1.3、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3.1、知识点1:mysqldumpslow - 总结缓慢的查询日志文件4、实验4.1、实验14.1.1、实验目的4.1.2、实验前准备4.1.3、实验步骤4.1.4、实验结论5、总结1、原题 1.1…...

数据采集 - 笔记 2
1快速实现西门子S7系列PLC数据采集 快速实现西门子S7系列PLC数据采集 - 知乎 2 什么是时序数据库? 时序数据库(Time Series Database)是一种特殊类型的数据库,用于存储和处理时间序列数据。时间序列数据是指按时间顺序排列的数…...

电子技术——数字IC技术,逻辑电路和设计方法
电子技术——数字IC技术,逻辑电路和设计方法 在我们之前的学习中,我们学习了CMOS技术,然而CMOS技术并不是唯一的数字逻辑技术,因此,本节系统的介绍当今使用的数字技术和逻辑电路族。 数字IC技术和逻辑电路族 逻辑电…...

[ROS2 知识] 包依赖关系和rosdep详述
一、说明 如果你建立一个工作空间,试图将所有包的依赖项搞明白,或者期望将包的依赖项全部安装到工作空间中,您看本文是正确选择。本文将解释如何使用 rosdep 管理外部依赖项。 二、介绍rosdep 2.1 rosdep是何物? rosdep 是 ROS 的依赖管理实用程序,可以与 ROS 包和外部库…...

mysql创建索引导致死锁,数据库崩溃,完美解决方案
文章目录写在前面一、短事务场景下,执行DDL语句场景分析1、短事务场景下,执行表字段添加操作2、短事务场景下,执行表字段修改操作3、短事务场景下,执行表字段删除操作(1)往里添加一条数据试试4、短事务场景…...

c++11 标准模板(STL)(std::unordered_map)(八)
定义于头文件 <unordered_map> template< class Key, class T, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator< std::pair<const Key, T> > > class unordered…...

企业ISO体系认证办理,可以自行申请吗?为什么都要找咨询公司?
企业ISO体系认证办理,可以自行申请吗?为什么都要找咨询公司? 很多人认为ISO咨询公司为中介机构,希望直接找认证公司进行认证。其实认证机构担任的是认证审核职责,咨询机构担任的是咨询职责。按中国国家任可监委员会的…...

二、Neo4j源码研究系列 - 单步调试
二、Neo4j源码研究系列 - 单步调试 一、背景介绍 上一篇我们已经把了neo4j的源码准备以及打包流程完成了,本篇将讲解如何对neo4j进行单步调试。对于不了解如何编译打包neo4j的读者,请阅读《一、Neo4j源码研究系列 - 源代码准备》。 大纲: …...

基于Qt WebEngine 的Web仪器面板GUI程控技术
随着IIoT的发展,很多工业仪器也具备了远程管理的GUI。与早期使用串口进行命令交互不同,这些GUI可以直接在远程呈现数据。 作为希望对仪器、软件进行二次开发的小公司来说,会遇到GUI人工操作转自动化的需求。在无法通过串口等传统接口进行自动…...

海康摄像头使用RTSP
1.协议格式。海康威视IP摄像头rtsp协议地址如下:rtsp://[username]:[passwd][ip]:[port]/[codec]/[channel]/[subtype]/av_stream主码流:rtsp://admin:12345192.168.1.64:554/h264/ch1/main/av_streamrtsp://admin:12345192.168.1.64:554/MPEG-4/ch1/mai…...

编程语言分类
目录 ❤ 机器语言 机器语言的编程 ❤ 汇编语言 ❤ 高级语言(编程语言) 编译型 解释型 ❤ 动态语言和静态语言 ❤ 强类型定义语言和弱类型定义语言 ❤ 主流语言介绍 C语言 C java python JavaScript SQL PHP python从小白到总裁完整教程目录:https://blog…...

[nodejs开发] typescript引入js模块或文件
首先更改tsconfig.json 中的compilerOptions属性:"moduleResolution": "Node"假设有一个abc.js其内容如下:var Circle (function () {function Circle() {}Circle.prototype.draw function () {console.log("Cirlce is drawn…...

小帮软件机器人应用于通信集团财务数据填报、编制、稽核、银企对账
某大型通信集团是国有控股通信运营服务提供商,主要从事国内外通信设施服务业务、固定通信业务、移动通信业务、数据通信业务、网络接入业务、卫星国际专线业务和通信业务相关系统集成业务,管辖20多家子(分)公司、服务运营和支持网…...

37. CF-Weights Distributing
链接 这是一个比较经典的题目。容易想到求出两段路径重合的部分,然后贪心的放权值。那么跑三次最短路,枚举重合部分的端点即可。 正解没什么好说的。这题有趣的地方在于,如果数据比较弱,可能会把一些错误做法放过去。 一种错误…...

百丽时尚×优维科技×道客战略启动「云原生一体化项目」
3月7日,由百丽时尚集团(以下简称:百丽时尚)联合优维科技、道客共同举办的「云原生一体化项目启动会」在深圳百丽国际大厦圆满落幕,项目合作三方齐聚一堂,就云原生一体化建设战略方案达成合作共识࿰…...

小诺开源技术
小诺开源技术 文章目录小诺开源技术前言页面演示介绍文档学习建议登录地址下载地址前言 近期接触了小诺开源技术的一个前端框架,底层是蚂蚁框架,感觉很好用,不过需要稍微学习并适应一下,推荐给大家,本篇仅用于学习&am…...

AidLux AI应用案例悬赏选题 | 纺织品表面瑕疵检测
AidLux AI 应用案例悬赏征集活动 AidLux AI 应用案例悬赏征集活动是AidLux推出的AI应用案例项目合作模式,悬赏选题将会持续更新。目前上新的选题涉及泛边缘、机器人、工业检测、车载等领域,内容涵盖智慧零售、智慧社区、智慧交通、智慧农业、智能家居等…...

UE官方教程笔记02-实时渲染基础下
对官方教程视频[官方培训]02-实时渲染基础下 | 陈拓 Epic的笔记没听懂的地方就瞎写反射实时渲染中反射是一个非常有挑战的特性UE中有多种不同的方案,各有各的优势和缺点反射捕获屏幕空间反射平面反射LumenRT Reflection反射捕获在指定位置捕获一张Cube Map需要预计算…...

grep命令——在文件中搜索指定的文本模式
grep是英文词组“global search regular expression and print out the line”的缩写,意思是全局搜索正则表达式,并将结果输出。 通常将grep命令与正则表达式搭配使用,命令选项作为搜索过程中的补充或对输出结果的筛选,命令模式十…...

数据结构刷题(二十二):90子集II、491递增子序列、46全排列
1.子集II题目链接思路:这是一道标准的组合问题数组排序去重。依然是使用回溯。注意:去重代码只需要判断同一树层上是否有重复,同组合总和II(https://blog.csdn.net/xiaomingming99/article/details/129396344)解法&…...

AI+人类,实现高效网络安全
导语 聊天机器人和生成式人工智能(如 ChatGPT)突然成为主流让很多人感到担忧。很多人开始担忧,人工智能取代人的时代已经到来。 幸运的是,事实并非如此。 更有可能的情况是,人类将与 AI 合作创建工作角色的混合模型。…...

牛客小白月赛68【A-E】
文章目录A.Tokitsukaze and New Operation【模拟】B.Tokitsukaze and Order Food Delivery【模拟、特判】C.Tokitsukaze and Average of Substring【暴力、前缀】D.Tokitsukaze and Development Task【记忆化搜索】E.Tokitsukaze and Colorful Chessboard【预处理,二…...

WIFI P2P架构
WI-FI P2P定义架构3个组件组织结构技术标准P2P DiscoveryDevice Discovery(扫描)流程p2p probe 管理帧Group Formation(组网)GO Negotiation(GON)流程P2P Public Action管理帧Provision Discoveryÿ…...

架构师之中台思维_系统发展之路_结果和抽象之间平衡的艺术
父文章 如何成为一名架构师,架构师成长之路_golang架构师成长之路_个人渣记录仅为自己搜索用的博客-CSDN博客 任何系统的发展都是如此. 1. 业务增长 2. 烟囱增长 _ 结果优先 _ 太快去抽象抽象不好 3. 太多的烟囱, 3.1 抽象复用为平台 3.2 面对更多新的业务,提供不同的枚举值…...

23届非科班选手秋招转码指南
1.秋招情况介绍 1.1自我介绍 我是一名23届非科班转码选手,本硕均就读于某211院校机械专业,秋招共计拿下12份offer,包括大疆创新、海康威视、联发科技、理想汽车、中电28、阳光电源等各行业、各种性质企业的意向。主要的投递岗位为嵌入式软件…...

《传感器技术》考试学习笔记
文章目录一、选择题二、简答题1.什么是传感器?传感器的共性是哪些?2.差动变气隙式传感器电感传感器的灵敏度推导过程是什么(推导公式)?与单极性进行比较它们的优缺点是哪些?3.霍尔传感器如何进行微位移测量…...

第十五章 opengl之高级OpenGL(模板测试)
OpenGL模板测试模板函数物体轮廓模板测试 当片段着色器处理完一个片段后,模板测试就会开始执行。类似于深度测试,模板测试也可能会丢弃片段。被保留的片段会进入深度测试,可能会丢弃更多的片段。 模板测试是根据模板缓冲来进行的。一个模板缓…...