设计模式笔记:策略模式 (Strategy Pattern)一、一句话概括定义一系列算法,将每一个算法封装起来,并使它们可以互相替换。此模式让算法的变化独立于使用算法的客户。
二、为什么需要它 (Why - The Pain Point)想象一下,你正在开发一个鸭子模拟游戏。你有各种各样的鸭子,比如 MallardDuck(绿头鸭)、RedheadDuck(红头鸭)等。所有的鸭子都会游泳(swim())和呱呱叫(quack()),所以你可能会设计一个 Duck 基类。
12345abstract class Duck { public void quack() { System.out.println("Quack quack!"); } public void swim() { System.out.println("Swimming..."); } public abstract void display();}
现在,需求变更,鸭子需要会飞(fly())。一个很 ...
设计模式笔记:解释器模式 (Interpreter Pattern)一、一句话概括给定一种语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
二、为什么需要它 (Why - The Pain Point)在某些特定领域,你可能需要处理一些简单、重复的指令或表达式。例如:
搜索引擎:用户输入 “cat AND (dog OR bird)”。
数学计算器:处理 “3 + 4 * 2”。
机器人控制:解析 “MOVE FORWARD 10; TURN RIGHT;”。
痛点:如果为每一种可能的表达式都写一堆 if-else 或 switch 逻辑来处理,代码会变得极其复杂、难以维护和扩展。你需要一种结构化的方式来表示和解析这些“迷你语言”。
核心问题:如何为一个简单的语言构建一个解析引擎,使其能够轻松地解释和执行该语言的指令?
三、它是什么 (What - The Solution)解释器模式建议为语言中的每条语法规则创建一个类。然后,将一个句子表示成一个由这些类的实例构成的抽象语法树(AST, Abstract Syntax Tree)。最后,通过 ...
设计模式笔记:观察者模式 (Observer Pattern)一、一句话概括定义了对象之间一种一对多的依赖关系,当一个对象(被观察者/主体)的状态发生改变时,所有依赖于它的对象(观察者)都会得到通知并自动更新。
二、为什么需要它 (Why - The Pain Point)想象一下一个气象站应用。我们有一个 WeatherData 对象,它负责从硬件传感器获取最新的气象数据(温度、湿度、气压)。同时,我们有多个布告板需要展示这些数据:
CurrentConditionsDisplay:显示当前的天气情况。
StatisticsDisplay:显示平均/最高/最低气温。
ForecastDisplay:根据气压变化预测天气。
糟糕的设计(紧密耦合):
WeatherData 对象直接持有所有布告板的引用,并在数据更新时,手动调用每个布告板的特定更新方法。
12345678910111213141516171819// 痛点:WeatherData 知道所有具体的布告板类public class WeatherData { private ...
设计模式笔记:访问者模式 (Visitor Pattern)一、一句话概括将数据结构和作用于该结构上的操作相分离。它允许你在不修改数据结构类的前提下,为这些类添加新的操作。
二、为什么需要它 (Why - The Pain Point)想象一下,你有一个表示文档结构的对象模型(一个组合模式的应用),包含 Paragraph(段落)和 Image(图片)等元素。
1234interface DocumentElement { /* ... */ }class Paragraph implements DocumentElement { /* ... */ }class Image implements DocumentElement { /* ... */ }// Document is a collection of DocumentElement
现在,你需要对这个文档执行多种操作:
导出为 HTML:Paragraph 需要被转换为 <p> 标签,Image 需要被转换为 <img> 标签。
提 ...
设计模式笔记:迭代器模式 (Iterator Pattern)一、一句话概括提供一种统一的方法来顺序访问一个聚合对象(容器)中的各个元素,而无需暴露该对象的内部表示。
二、为什么需要它 (Why - The Pain Point)我们有各种各样的数据集合,比如 ArrayList(基于数组)、LinkedList(基于链表)、HashSet(基于哈希表)、树、图等。每种数据结构的内部实现和元素存储方式都大相径庭。
痛点:如果客户端代码想要遍历这些不同的集合,就必须为每一种集合编写不同的遍历逻辑。
12345678910// 痛点:客户端代码与集合的具体实现紧密耦合// 遍历数组for (int i = 0; i < array.length; i++) { ... }// 遍历链表 (假设)Node node = list.getHead();while (node != null) { // ... process node.getData() ... node = node.getNext();}
这种方式的问题是:
客户 ...
设计模式笔记:抽象工厂模式 (Abstract Factory Pattern)一、一句话概括提供一个接口,用于创建一整套相互关联或相互依赖的对象(一个产品族),而无需指定它们具体的类。
二、为什么需要它 (Why - The Pain Point)工厂方法模式解决了单个产品的创建问题。但如果我们需要创建的是一系列产品,并且要保证这些产品能相互兼容、协同工作,情况就变得复杂了。
想象一下,你正在开发一个跨平台的 UI 框架,需要支持 Windows 和 macOS 两种操作系统风格。
在 Windows 上,你需要创建 WindowsButton, WindowsCheckbox, WindowsTextField。
在 macOS 上,你需要创建 MacOSButton, MacOSCheckbox, MacOSTextField。
痛点:
产品兼容性问题:你绝对不希望在同一个界面上出现一个 Windows 风格的按钮和一个 macOS 风格的复选框。这会造成 UI 风格混乱,用户体验极差。必须保证,一旦选择了某个主题(如 Windows),所有被创建的组件都必须是该主题下的。 ...
这个模式主要用于实现“撤销/重做”(Undo/Redo)功能,或者在不破坏对象封装性的前提下保存和恢复其状态。
设计模式笔记:备忘录模式 (Memento Pattern)一、一句话概括在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后能将该对象恢复到原先保存的状态。
二、为什么需要它 (Why - The Pain Point)想象一下,你正在开发一个文本编辑器或一个游戏。用户可能需要撤销他们之前的操作。例如,在编辑器中写了一段文字,然后想回到几分钟前的版本;或者在游戏中,角色走错了一步,想回到上一个存档点。
要实现这个功能,你需要能够:
在某个时间点,保存对象(如编辑器文档、游戏角色)的当前状态。
在需要的时候,用之前保存的状态来恢复该对象。
直接实现会遇到什么问题?
一个天真的想法是,直接从外部访问并复制对象的所有内部字段(private 成员)。
12345678910111213141516171819class Editor { private String content; private ...
OpenGL函数加载机制:深入理解 wglGetProcAddress1. 为什么需要 wglGetProcAddress?在Windows上使用OpenGL,你可能会发现一些核心OpenGL函数可以直接链接(比如glClear、glBegin等),但更多现代OpenGL函数(例如你提到的glGenBuffers、glCreateShader等)却不能直接链接。这是因为:
历史原因与版本演进: OpenGL规范不断更新,新的函数层出不穷。为了保持向后兼容性,Windows的OpenGL库(opengl32.lib/opengl32.dll)只提供了一个相对“静态”的、较老版本的OpenGL 1.1核心函数集。
驱动实现: 真正的OpenGL实现是在显卡驱动程序中。驱动程序会根据你的显卡型号和驱动版本,提供最新的、高度优化的OpenGL函数实现。
动态加载: 应用程序需要一种机制来“查询”并“获取”这些由显卡驱动提供的,比OpenGL 1.1更新的函数指针。wglGetProcAddress就是用来实现这一动态加载的关键函数。
2. wglGetProcAddress ...
这个模式的核心思想是“请求的封装”,它在实现撤销/重做、任务队列、事务操作等方面发挥着至关重要的作用。
设计模式笔记:命令模式 (Command Pattern)一、一句话概括将一个请求封装成一个对象,从而可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
二、为什么需要它 (Why - The Pain Point)想象一下,你正在设计一个智能家居遥控器。这个遥控器上有很多按钮,每个按钮可以控制不同的设备(灯、风扇、电视等)执行不同的操作(打开、关闭、调高音量等)。
直接实现的糟糕设计:
1234567891011121314151617181920// 各种设备类class Light { public void on() { ... } public void off() { ... } }class Fan { public void high() { ... } public void off() { ... } ...
设计模式笔记:享元模式 (Flyweight Pattern)一、一句话概括通过共享尽可能多的相似对象来有效地支持大量细粒度对象的复用,从而最大限度地减少内存占用和对象创建的开销。
二、为什么需要它 (Why - The Pain Point)想象一个场景:你正在开发一个图形编辑器或一个游戏,需要在屏幕上绘制数百万个粒子、树木或字符。
12345678910111213141516class Particle { // 每个粒子都有很多属性 private int x, y; // 位置 (经常变化) private double velocity; // 速度 (经常变化) private Color color; // 颜色 (可能只有几种) private Sprite sprite; // 粒子贴图 (可能只有几种) private int size; // 大小 (可能只有几种) // ...}// 客户端代码List<Particle> pa ...