memento
1. 什么是备忘录模式?备忘录模式(Memento Pattern)用于在不破坏封装的前提下,捕获并保存对象的内部状态,以便之后将其恢复。核心思想是:状态快照应对外保持不透明,只有创建它的对象才能读写其内容。 2. 为什么需要备忘录模式?在需要撤销/重做、事务性修改或阶段性试错的场景中,我们希望随时回到某个稳定的历史状态。如果将内部状态直接暴露给外部组件,会破坏封装并引入脆弱耦合。备忘录提供了一种更稳妥的做法:外部只负责保存与传递快照,而不窥视其内容;状态的读写权严格归属于原始对象本身。 3. 备忘录模式的实现(go)下面的实现采用“封装最严格”的变体:看护者只能看到窄接口 Memento,无法读取或修改状态;只有发起者可以访问具体备忘录以进行恢复。 123456789101112131415161718192021222324252627282930313233type Memento interface{ mementoMarker() }type memento struct{ content string cursor...
observer
1. 什么是观察者模式?观察者模式(Observer Pattern)用于在对象状态变化时,通知依赖它的多个观察者,实现一种一对多的订阅关系。被观察者只负责发布事件,不关心有多少观察者、它们如何处理,达到发布方与订阅方的解耦。 2. 为什么需要观察者模式?当一个对象的变化需要联动多个组件时,若直接在对象内部逐个调用这些组件,将产生紧耦合和复杂的依赖。当组件增删或行为变化时,被观察者也不得不调整。通过观察者模式,我们将事件的发布与处理分离:被观察者只负责发出信号,观察者各自处理,从而降低耦合、提高扩展性。 3. 观察者模式的实现(go)1234567891011121314151617181920212223242526272829303132333435363738394041424344type Observer interface { Update(event string, data any)}type Subject interface { Register(o Observer) Unregister(o...
binary constraint matching
1. 抽象受到力扣1. 两数之和以及类似问题的启发,抽象出如下模板: 给定一个整数数组arr,令$x,y \in arr$,且$x,y$不能是同一个元素。若$f(x,y)=K$,给定$f,K$,求所有满足条件的${x,y}$。 伪代码如下 123456789101112131415//input : arr, f, K//output : all pairs of x, y in arr such that f(x, y) = K//assumption : f(x,y)=k <=> g(x)=h(y), and g,h both are well-defined functionsalgorithm binary-constraint-matching(arr, K, f): hash table := empty hash table, value -> list ans := empty set for each x in arr; do if h(x) in hash table; then ...
chain of responsibility
1. 什么是责任链模式?责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它将请求的发送者和接收者解耦,将这些处理者连成一条链。链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理,或是中途退出。 2. 为什么需要责任链模式?当处理一个请求、但处理步骤有多种、且依赖于不同的条件时,一种最直观的写法可能是一个巨大的 if-else 结构: 1234567891011func handle(request *Request) { if conditionA(request) { // 处理 A } else if conditionB(request) { // 处理 B } else if conditionC(request) { // 处理 C } else { //...
command
1. 什么是命令模式命令模式是一种行为设计模式,它将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。简单来说,就是将请求的发送者和请求的具体操作完全解耦。 2. 为什么需要命令模式?命令模式的核心价值在于解耦。如果没有命令模式,调用者(比如一个按钮 Button)需要直接引用并调用一个具体的操作(比如一个文档 Document 的 save() 方法)。这会导致 Button 和 Document 紧密耦合,Button 无法被复用到其他操作上。 通过引入命令对象,调用者不再关心命令的接收者是谁,也不关心操作如何执行。它只知道“我需要执行这个命令”。 这样的话,调用者和接收者之间没有任何直接引用,各自可以独立变化。而且添加新的命令非常容易,只需创建新的具体命令类,而无需修改现有代码,符合开放/封闭原则。 3. 命令模式的实现 (Go)中间件: 1234567891011121314151617181920212223242526272829303132333435// Command 接口定义了一个执行操作的方法type Command...
iterator
1. 什么是迭代器模式迭代器模式(Iterator Pattern)是一种行为设计模式,它提供一种方法来顺序访问一个聚合对象(Aggregate Object)中的各个元素,而又无需暴露该对象的内部表示。 无论操作的是一个数组、一个链表、一棵树还是一个哈希表,都可以用同样的客户端方式去遍历它(比如一个 for-each 循环),而不关心底层的具体的遍历方式是dfs还是bf或者其他。 它将遍历的逻辑从聚合对象中分离出来,放入一个单独的迭代器对象中。这样,容器只负责存储数据,而迭代器负责遍历数据。 2. 为什么需要迭代器模式?如果没有迭代器模式,客户端代码需要知道聚合对象的内部结构才能进行遍历。例如,遍历数组需要用索引,遍历链表需要用 next 指针。这会导致客户端与数据结构紧密耦合。 客户端无需关心容器的内部实现(是 slice、map 还是 linked...
closest equal element queries
题目 12345678910111213141516171819vector<int> solveQueries(vector<int>& nums, vector<int>& queries) { map<int,vector<int>>mp; for(int i=0;i<nums.size();++i){ mp[nums[i]].push_back(i); } int n = queries.size(); vector<int>ans(n,-1); for(int j=0;j<n;++j){ int q = queries[j]; auto & vec = mp[nums[q]]; if(vec.size()==1){ ...
flyweight
1. 什么是享元模式享元模式是一种结构型设计模式,它通过共享相同状态的对象来减少内存占用和提高性能。 2. 为什么需要享元模式我们用一个“在地图上种树”的例子来理解。 2.1. 问题:内存爆炸假设要在地图上种 100 万棵树。每棵树都有: 坐标:每棵树都不同。 类型信息:如名称(松树)、颜色(绿色)、纹理图片等。类型是有限的,比如只有几种。 如果为每棵树都创建一个包含所有信息的对象,Texture(纹理图片)这份可能很大的数据会被重复存储 100 万次,导致内存爆炸。 1234567// 传统方式:每个对象都包含所有数据type Tree struct { X, Y int Name string Color string Texture []byte // 假设这份数据很大} 该如何解决这个问题? 2.2. 方案:享元模式享元模式的核心是分离并共享相似对象中的共同部分,以减少内存占用。 我们将对象的状态分为两种: **内部状态 (Intrinsic State)**:可共享、不随环境改变的部分。在例子中是 Name,...
proxy
1. 什么是代理模式代理模式是一种结构型设计模式,它通过引入一个代理对象来控制对另一个对象的访问。代理对象可以在客户端和目标对象之间添加额外的功能,如延迟加载、访问控制、日志记录等。 2. 为什么需要代理模式代理模式的核心价值在于在不改变原始对象(目标对象)代码的前提下,增加额外的控制和功能。它像一个中介,隔离了客户端和真实对象,并在中间“做手脚”。 3. 代理模式的实现 (Go)我们用 Go 实现一个保护代理的例子。假设我们有一个 Web 服务器,希望通过一个 Nginx 代理来限制用户的访问速率。 客户端、代理和真实服务都应遵循同一个接口,这样代理才能“伪装”成真实服务。 1234// Server 是代理和真实服务器的通用接口type Server interface { HandleRequest(url, method string) (int, string)} 创建真实服务 (RealSubject) 这是我们真正要保护的后端应用。 123456789101112// Application 是我们的后端真实服务type...
composite
1. 什么是组合模式组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得客户端可以统一地处理个别对象和对象组合。 2. 为什么需要组合模式组合最主要的功能是在整个树状结构上递归调用方法并对结果进行汇总。 3. 组合模式的实现(go)假定一个文件系统,其中包含文件和目录。目录可以包含其他文件和目录。 现在我们需要搜索文件系统中是否包含某个文件。 12345678910111213141516171819202122232425262728293031323334type Component interface { Search(keyword string)}type Directory struct { Name string children []Component}func (d *Directory) Search(keyword string) { if d.Name == keyword...