Hi, 我是 W10N

这里收集整理了一些技术资料(大部分是转载的,经常用到的有整理过),希望能帮助到有需要的人。

OpenTofu 入门:用 IaC 在 AWS 创建 VPC 和 EC2

什么是 OpenTofu OpenTofu 是 Terraform 的开源分支,用于以声明式的方式管理云基础设施(IaC,Infrastructure as Code)。 与 AWS CLI 的区别: OpenTofu AWS CLI 方式 声明式(描述终态) 命令式(执行具体操作) 状态管理 有 state 文件,追踪资源状态 无状态 典型场景 创建/销毁一整套基础设施 查询、临时操作 OpenTofu 和 AWS CLI 都直接调用 AWS API,不存在封装关系。 核心概念 Provider Provider 是 OpenTofu 操作各家云服务的插件,tofu init 时自动下载。 required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } Resource vs Data Source resource — 创建资源(EC2、VPC、安全组等) data — 查询已有信息,不创建资源 # 查询最新的 Amazon Linux 2023 AMI(不创建资源) data "aws_ami" "al2023" { most_recent = true owners = ["137112412989"] filter { name = "name" values = ["al2023-ami-2023.*-x86_64"] } } # 创建 EC2 实例(使用上面查到的 AMI ID) resource "aws_instance" "server" { ami = data.aws_ami.al2023.id instance_type = "t2.nano" } Variables 变量分两个文件: ...

2026-04-29 · 5 min · 864 words · -

组合模式, Composite Pattern

Composite Pattern, 组合模式 组合模式(Composite Pattern)将对象组合成树状层次结构,使客户端对单个对象(叶子节点)和组合对象(容器节点)具有一致的访问方式。 核心思想:部分与整体的统一接口。 角色: Component:抽象组件,定义叶子和容器的公共接口 Leaf:叶子节点,没有子节点,实现具体操作 Composite:容器节点,包含子组件,将操作委托给子节点 UML 类图 classDiagram class FileSystemNode { <<interface>> +getName() String +getSize() long +print(indent String) } class File { -name String -size long +getName() String +getSize() long +print(indent String) } class Directory { -name String -children List~FileSystemNode~ +add(node FileSystemNode) +remove(node FileSystemNode) +getName() String +getSize() long +print(indent String) } FileSystemNode <|.. File : implements FileSystemNode <|.. Directory : implements Directory o-- FileSystemNode : contains 示例:文件系统 文件系统是 Composite 模式的经典场景——文件夹可以包含文件或其他文件夹,但对外都提供统一的 getSize() 接口。 ...

2026-04-16 · 2 min · 363 words · -

k8s command

k8s command commands kubekey https://github.com/kubesphere/kubekey Rancher https://rancher.com/ archlinux install k8s ubuntu install k8s commands # 查看某一个 pod 配置 kubectl get pod <pod-name> -n <namespace> -o yaml # 找到 Pod 所属的 Controller(通常是 Deployment) kubectl get pod <pod-name> -o jsonpath="{.metadata.ownerReferences[0].name}" # 查看 Deployment 的 YAML 启动命令 kubectl get deployment bgp-opt-backend -o yaml # exec api kubectl exec -it "$(kubectl get pods | grep -Eo '^[^ ]+' |grep api)" -- bash # pod kubectl get pod -A -o wide # 查看 pod, 比如能看到镜像版本 kubectl describe pods pod0 # configmap kubectl apply -f redis-config.yaml kubectl get configmap kubectl get configmap -n namespace0 kubectl edit configmap configmap0 kubectl delete configmap configmap0 # 显示集群信息 kubectl cluster-info kubectl cluster-info dump # 查询所有节点标签信息 kubectl get node -o wide --show-labels # kube-system namespace 的 pod kubectl get pods -n kube-system kubectl label node 192.168.0.212 gpu=true kubectl get node -L gpu kubectl get node -L kubernetes.io/arch # delete lable kubectl label node minikube disktype- kubectl describe node node0 ## 节点关机操作 ```bash # 1. 标记节点为不可调度(防止新 Pod 调度到该节点) kubectl cordon <node-name> # 2. 驱逐节点上的 Pod(优雅地将 Pod 迁移到其他节点) kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data # 3. 验证节点上是否还有 Pod 运行 kubectl get pods --all-namespaces -o wide | grep <node-name> # 4. 关机 sudo poweroff # 5. 节点重新上线后,恢复调度(取消不可调度状态) kubectl uncordon <node-name> 查看 pod 状态 kubectl get pods –all-namespaces ...

2026-03-10 · 16 min · 3341 words · -

openwrt basic, opkg basic, ipk

openwrt basic, opkg basic, ipk commands # 查看 openwrt 版本 cat /etc/openwrt_release # 更新所有软件,包括 OpenWRT 内核、固件等 opkg list-upgradable | cut -f 1 -d ' ' | xargs opkg upgrade wan dns 在 wan 口设置里的“高级设置”选项里去掉"使用端局通告的DNS服务器"的勾选就可以使用自定义的DNS服务器 ssh port vim /etc/init.d/dropbear validate_section_dropbear > port ssh public key vim /etc/dropbear/authorized_keys dns 配置 查看本机的 DNS 配置: $ cat /etc/resolv.conf search lan nameserver 127.0.0.1 发现使用的是本机 DNS 服务器,即 dnsmasq。 查看 dnsmasq 配置: $ cat /etc/dnsmasq.conf 手动指定上游 dns vi /etc/dnsmasq.conf server=223.5.5.5 server=223.6.6.6 openwrt 改IP vi /etc/config/network opwnert init opkg install coreutils-nohup opkg install ipset opkg remove dnsmasq opkg install dnsmasq-full openwrt cron /etc/init.d/cron start /etc/init.d/cron enable crontab -e crontab -l x86, firmware download https://downloads.openwrt.org/releases/19.07.6/targets/x86/ ...

2022-08-11 · 3 min · 586 words · -

Conflict Check

此文用于记录在 AI 时代到来之前我手搓的最后一个复杂模块. 这个 conflict check 模块的重写是在 2024 年,历时约 3 个月,当时我还没有开始大规模使用 AI 辅助编程。重写的时候注意力都在功能需求上,并没有想「要用哪种设计模式」,只是在纠结怎么把问题拆清楚、用面向对象的方式把责任分开、把可能变化的部分封装起来。Redis 里的缓存数据是嵌套的树形结构,解析时写了几个递归调用——当时认为是最复杂的几个函数。 这个文档写于此后。某次和一个朋友聊天,对方问起对设计模式有没有了解,当时长期没有专门研究过,没说出个所以然。后来那个问题偶尔还会浮上来,然后有一天和 conflict check 关联到了起来, 然后用 Copilot + Claude Sonnet 4.6 分析了一下 — 有些设计模式接近标准实现,有的因业务结构或 Python 语言特性而有所偏差,还有两个(Builder 和 State)目前只是符合模式意图、需要重构才能达到标准结构。整理的过程中还发现了有性能优化空间的地方。 背景 防火墙策略在应用到设备之前,需要先在缓存中进行冲突检测。“网络编排器” 将每台设备的数据缓存在 Redis 中,每份 profile 包含三类数据:地址对象和分组、服务对象和分组,以及策略列表。 每条策略的关键字段: src:源地址数组,每个元素是一个 address object name 或 address group name dst:目标地址数组,结构与 src 相同 service:服务数组,每个元素是一个 service object name 或 service group name 地址对象和服务对象共用同一种数据结构,各自包含两种角色: object:基础对象,value 是实际 IP 地址/CIDR 网段(address)或协议/端口(service)的数组 group_object:分组对象,value 是 object name 或另一个 group_object name 的数组 group 和 object 形成嵌套结构:一个 group 的 value 列表里,既可以直接引用 object,也可以引用其他 group,形成递归树。地址对象和服务对象结构相同,因此 PolicyObject 类可以统一表达这两种类型,同时处理 src、dst、service 的解析。 ...

2026-05-14 · 6 min · 1181 words · w1100n

代理模式, proxy pattern

代理模式, proxy pattern 为其他对象提供一种代理以控制对这个对象的访问。 代理模式,即Proxy,它和 Adapter 模式很类似。我们先回顾Adapter模式,它用于把A接口转换为B接口: Adapter 模式 public BAdapter implements B { private A a; public BAdapter(A a) { this.a = a; } public void b() { a.a(); } } Proxy模式 而Proxy模式不是把A接口转换成B接口,它还是转换成A接口: public AProxy implements A { private A a; public AProxy(A a) { this.a = a; } public void a() { this.a.a(); } } 看起来 Proxy 只是把 A 接口又包了一层,这有什么意义呢? ...

2026-04-16 · 1 min · 185 words · -

创建者模式, 建造者模式, Builder

创建者模式, 建造者模式, Builder pattern 定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 使用场景 多个部件或零件,都可以装配到一个对象中,但产生的结果又不相同时。 当初始化一个对象特别复杂的时候,比如参数多,而且很多参数都有默认值。 GoF Builder 模式包含四个角色: 抽象建造者 (Builder):给出一个抽象接口,以规范产品对象各个组成成分的建造。 具体建造者 (ConcreteBuilder):实现抽象建造者声明的接口,一步一步完成创建产品实例的操作;建造完成后提供产品实例。 指挥者 (Director):调用具体建造者以创建产品对象。 产品 (Product):建造中的复杂对象。 GoF Builder 示例:RTF 文档转换器 RTF 背景 RTF(Rich Text Format,富文本格式)是微软 1987 年推出的一种文档格式,用纯文本加控制命令描述带格式的文档。一段 RTF 内容长这样: {\rtf1 Hello {\b World}\par} {\b ... } 表示加粗 \par 表示段落结束 RTFReader(Director)的工作是逐个扫描这些 token:遇到 \b 就调 convertFontBold(true),遇到普通字符就调 convertCharacter(c),遇到 \par 就调 convertParagraph()。它自己不生产任何输出,只负责解析结构、驱动 Builder。虽然 RTF 现在已经很少用了,但"解析器解析 → 转换器输出不同格式"这个模型在现代依然普遍(如 Markdown 解析器输出 HTML / PDF / DOCX)。 这是 GoF 原书使用的经典案例。同一份 RTF 文档,Director(RTFReader)负责解析 token 流,每遇到字符、加粗标记、段落标记就调用 Builder 对应的方法。Director 只管读懂结构,Builder 只管决定输出,两者通过接口解耦:parse() 接收的是 TextConverter 接口,不需要知道背后的具体类型,也不需要知道最终输出格式——它只是把 RTF 语义事件翻译成接口调用,由各 ConcreteBuilder 自己决定如何响应:ASCIIConverter 忽略格式标记只保留字符,HTMLConverter 将加粗转为 <b> 标签,TeXConverter 转为 \textbf{} 命令。 ...

2026-04-16 · 4 min · 830 words · -

Martin Fowler 主要设计模式

Martin Fowler 是《重构》《企业应用架构模式》《领域特定语言》等经典书籍的作者,也是 ThoughtWorks 首席科学家。他提出或系统整理了大量在工业界广泛应用的设计模式,涵盖对象建模、企业架构和分布式系统三个层面。 本文选取其中最具代表性的几个模式进行介绍。关于企业应用架构模式中的 Repository、Unit of Work、Front Controller 等,见 企业应用架构模式。 《企业应用架构模式》 Patterns of Enterprise Application Architecture(PoEAA) Special Case(特殊情况) 来源: Patterns of Enterprise Application Architecture(2002) 问题 方法在遇到无法正常处理的输入时,通常有两种选择:返回 null 或抛出异常。两者都把处理责任推给调用方,导致 null 判断或 try/catch 散布在代码各处。 // 调用方被迫到处写 null 判断 Customer customer = customerRepository.findById(id); if (customer == null) { return "unknown"; } return customer.getName(); 解决方案 为"无法正常处理"的情况创建一个实现相同接口的特殊对象,让它封装默认行为。调用方无需判断,直接调用即可。 public interface Customer { String getName(); boolean isNull(); } public class UnknownCustomer implements Customer { @Override public String getName() { return "Unknown"; } @Override public boolean isNull() { return true; } } // 仓储层返回特殊对象,而非 null public Customer findById(long id) { Customer c = db.find(id); return c != null ? c : new UnknownCustomer(); } // 调用方无需 null 判断 String name = customerRepository.findById(id).getName(); Special Case vs Null Object Null Object 是 Special Case 的一个特例——当特殊行为就是"什么也不做"时,就是 Null Object。Special Case 更通用:特殊对象可以有具体的默认行为,甚至代表一个有意义的领域概念(如"匿名用户"“未知账户"“空购物车”)。 ...

2026-05-15 · 3 min · 541 words · -

中介者模式, Mediator Pattern

中介者模式, Mediator Pattern 中介者模式(Mediator Pattern)定义一个中介对象来封装一系列对象之间的交互,使各对象不需要显式地相互引用,从而降低耦合度,并可以独立地改变它们之间的交互。 核心思想 当系统中多个对象之间存在复杂的多对多交互时,对象之间的依赖关系会形成网状结构,难以维护。中介者模式将这种网状结构转化为星形结构——所有对象只与中介者通信,由中介者协调各对象之间的交互。 不使用中介者:网状结构 graph LR A <--> B A <--> C B <--> C B <--> D C <--> D 使用中介者:星形结构 graph LR A <--> M[Mediator] B <--> M C <--> M D <--> M 角色 Mediator(抽象中介者):定义各同事对象通信的接口。 ConcreteMediator(具体中介者):实现协调逻辑,持有所有同事对象的引用。 Colleague(同事类):每个同事只知道中介者,通过中介者与其他同事交互。 示例:聊天室 聊天室是中介者模式的典型场景:用户之间不直接通信,而是通过聊天室(中介者)转发消息。 抽象中介者: public interface ChatRoom { void sendMessage(String message, User sender); void addUser(User user); } 具体中介者: ...

2026-04-16 · 2 min · 276 words · -

GOF 23 种设计模式, Design pattern

GOF 23 种设计模式, Design pattern 在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。 四位作者合称 GOF(四人帮,全拼 Gang of Four)。 分类 创建模式, Creational Patterns Simple Factory, 简单工厂 Factory Method 工厂方法 Abstract Factory 抽象工厂模式 Prototype, 原型 Builder, 建造者 Singleton, 单例 结构模式, Structural Patterns Facade, 外观 Proxy, 代理 Adapter, 适配器 Composite, 组合 Decorator, 装饰器 Bridge, 桥接 Flyweight, 享元 行为模式, Behavioral Patterns Template Method, 模板方法 Memento, 备忘录 Observer - 观察者 https://wiloon.com/observer Chain Of Responsibility, 责任链 Command, 命令模式 (别名: 动作模式(Action)或事务模式(Transaction)) State, 状态 Strategy, 策略 Mediator, 中介者 Interpreter, 解释器 Visitor, 访问者 Iterator, 迭代器 模式列表 单例 ( Singleton )模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 原型 ( Prototype )模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。 工厂方法 (Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。 抽象工厂 (AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。 建造者 (Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。 代理 (Proxy) 模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。 适配器 (Adapter) 模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 桥接 (Bridge) 模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。 装饰 (Decorator) 模式:动态的给对象增加一些职责,即增加其额外的功能。 外观 (Facade) 模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。 享元 (Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。 组合 (Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。 模板方法 (TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 策略 (Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。 命令模式 (Command):将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。 职责链 (Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。 状态 (State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。 观察者 (Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。 中介者 (Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。 迭代器 (Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 访问者 (Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。 备忘录 (Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。 解释器 (Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。 GoF: (Gang of Four,GOF设计模式) - 四人组 Design Patterns: Elements of Reusable Object-Oriented Software (即后述《设计模式》一书) ,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著 (Addison-Wesley,1995) 。这几位作者常被称为"四人组 (Gang of Four) “,而这本书也就被称为"四人组 (或 GoF) “书。 ...

2011-10-29 · 2 min · 377 words · -

责任链模式, Chain of Responsibility Pattern

责任链模式, Chain of Responsibility Pattern 责任链模式(Chain of Responsibility)将请求沿着一条处理者链传递,每个处理者决定是否处理该请求,或将其传递给链上的下一个处理者。请求的发送者无需知道最终由哪个处理者来处理,从而实现了发送者与接收者的解耦。 核心思想 不使用责任链时,请求方往往需要硬编码逻辑来判断应该由哪个对象处理,导致紧耦合和大量条件判断。责任链将这些处理者串联起来,请求沿链传递,直到被某个处理者处理(或到达链尾)。 角色 Handler(抽象处理者):定义处理请求的接口,通常包含设置下一个处理者的方法。 ConcreteHandler(具体处理者):实现处理逻辑,决定自己是否处理请求,如果不处理则转发给下一个处理者。 Client(客户端):构建责任链并向链头发起请求。 示例:Java Servlet Filter 链 Servlet 规范中,请求在到达 Servlet 之前会依次经过一组 Filter,每个 Filter 可以对请求/响应做处理,然后调用 chain.doFilter() 继续传递,或直接中断返回响应。 Request → LogFilter → AuthFilter → Servlet ↓ Response ← ← ← 抽象处理者(Servlet 规范定义,无需自己写): public interface Filter { void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; } 具体处理者: public class LogFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("→ 请求到达:" + ((HttpServletRequest) request).getRequestURI()); chain.doFilter(request, response); // 继续传递给下一个 Filter System.out.println("← 响应返回"); // 响应回传时也会经过这里 } } public class AuthFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String token = ((HttpServletRequest) request).getHeader("Authorization"); if (token == null || !isValid(token)) { ((HttpServletResponse) response).sendError(401, "Unauthorized"); return; // 中断链,不调用 chain.doFilter() } chain.doFilter(request, response); // 鉴权通过,继续传递 } private boolean isValid(String token) { return token.startsWith("Bearer "); } } FilterChain 的内部实现(容器负责构建,这里展示其原理): ...

2026-04-16 · 2 min · 250 words · -

State 状态模式

State Pattern, 状态模式 不同的状态,不同的行为;或者说,每个状态有着相应的行为。 何时使用 State 模式适合"状态的切换"。因为我们经常会使用 if-elseif-else 进行状态切换,如果针对状态的判断切换反复出现,就要联想到是否可以采取 State 模式了。 不只是根据状态,也有根据属性。如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高——经常会在数据表的尾部加上属性字段,用以标识记录中一些特殊性质,这种属性的切换又是随时可能发生的,就有可能要使用 State。 是否使用 “开关切换状态"和"一般的状态判断"有区别: 一般的状态判断:state 的值由另一个变量决定,二者没有关系。 if (which == 1) state = "hello"; else if (which == 2) state = "hi"; else if (which == 3) state = "bye"; 开关切换状态:state 的下一个值由当前值决定,像旋转开关一样。 if (state.equals("bye")) state = "hello"; else if (state.equals("hello")) state = "hi"; else if (state.equals("hi")) state = "bye"; 如果只有一个方向的切换,不一定需要 State 模式(建立很多子类会增加复杂性);但如果同一操作在多个状态下行为各不相同,且状态数量会增长,就应该考虑 State 了。 示例:未使用 State 模式 TCP 连接有三个核心状态:CLOSED、LISTEN、ESTABLISHED。对同一操作,不同状态的行为完全不同: public class TCPConnection { private String state = "CLOSED"; public void open() { if (state.equals("CLOSED")) { // 发送 SYN state = "ESTABLISHED"; } // LISTEN / ESTABLISHED 状态下忽略 } public void close() { if (state.equals("LISTEN")) { state = "CLOSED"; } else if (state.equals("ESTABLISHED")) { // 发送 FIN state = "CLOSED"; } // CLOSED 状态下忽略 } public void acknowledge() { if (state.equals("LISTEN")) { state = "ESTABLISHED"; } else if (state.equals("ESTABLISHED")) { // 处理数据 ACK } // CLOSED 状态下忽略 } } 随着状态增多,if-else 链会急剧膨胀,且每次新增状态都要修改所有方法。下面用 State 模式重构。 ...

2017-01-23 · 2 min · 358 words · -

基于原型的编程 (Prototype-based Programming)

注意:本文讲的是基于原型的编程范式,不是 GoF 设计模式中的 Prototype 模式。两者名字相同,但概念不同。 基于原型的编程是什么 基于原型的编程(Prototype-based programming)是面向对象编程的一种方式。与传统的基于类(class-based)的方式不同,它没有 class 的概念,对象直接从其他对象继承,又称为基于实例的编程(Instance-based programming)。 与基于类的编程的区别 基于类的编程(如 Java、C++): 先定义 class(类),class 描述对象的结构和行为 再通过 class 实例化出对象 对象的行为由其所属的 class 决定 基于原型的编程(如 JavaScript、Lua、Self): 没有 class,只有对象 对象直接从另一个对象(原型)继承属性和方法 可以在运行时动态修改对象,甚至修改原型 典型例子:JavaScript JavaScript 是最广为人知的基于原型的语言。每个对象都有一个内部指针指向它的原型对象,属性查找会沿着原型链向上查找。 const animal = { speak() { console.log("..."); } }; const dog = Object.create(animal); // dog 的原型是 animal dog.speak(); // 继承自 animal ES6 引入的 class 语法只是原型继承的语法糖,底层仍然是原型链。

2017-11-13 · 1 min · 57 words · -

Builder 模式与 Factory Method 模式的对比

原文:http://www.cnblogs.com/shenfx318/archive/2007/01/28/632724.html 代码示例为 C#。 Builder 与 Factory Method 同属 GoF 创建型模式,初学者容易混淆。本文通过将 Builder 模式一步步演化为 Factory Method,探讨两者的本质关系。 注:本文讨论的 Factory 指工厂方法(Factory Method),不是抽象工厂(Abstract Factory)。 Builder 模式的标准结构 Builder 模式由四个角色构成:抽象 Builder、具体 Builder、Director(指导者)、Product。 public interface IBuilder { void BuildPart1(); void BuildPart2(); Product GetResult(); } public class BuilderA : IBuilder { private Product product; public void BuildPart1() { product = new Product(); product.Add("Part1 build by BuilderA"); } public void BuildPart2() { product.Add("Part2 build by BuilderA"); } public Product GetResult() { return product; } } // Director 封装构建顺序 public class Director { public void Construct(IBuilder builder) { builder.BuildPart1(); builder.BuildPart2(); } } 客户端调用: Director director = new Director(); IBuilder builder = new BuilderB(); director.Construct(builder); Product product = builder.GetResult(); 逐步演化为 Factory Method 第一步:合并 Director 到 Builder Director 只是按固定顺序调用 Builder 的方法,如果构建顺序稳定,这个独立类显得多余。把 Construct() 合并进 Builder: ...

2012-10-12 · 2 min · 221 words · -

静态工厂方法 (Static Factory Method)

与 GoF 工厂方法的区别 静态工厂方法(Static Factory Method)不是 GoF 23 种设计模式之一,容易和 GoF 的"工厂方法模式(Factory Method Pattern)“混淆,两者本质不同: GoF 工厂方法模式 静态工厂方法 出处 GoF《设计模式》 Effective Java Item 1(Joshua Bloch) 本质 定义创建对象的接口,由子类决定实例化哪个类 用静态方法代替构造器来创建对象 是否 GoF 模式 ✅ 是 ❌ 不是,是编程惯用法(idiom) 静态工厂方法是 Joshua Bloch 在《Effective Java》Item 1 中推荐的编程惯例:用命名的静态方法代替构造函数。 基本概念 创建类的实例的最常见方式是用 new 调用构造方法。每执行一条 new 语句,都会在堆区产生一个新对象。假如类需要封装创建实例的细节、或控制实例数量,可以改用静态工厂方法。 典型例子:Class 实例由 JVM 在加载类时自动创建,程序无法用 new 创建 java.lang.Class 的实例(没有 public 构造方法)。为此,Class 提供了静态工厂方法: Class c = Class.forName("Sample"); // 返回代表 Sample 类的实例 相比构造方法的优势 1. 方法名可以携带语义 构造方法名必须与类名相同,所有重载版本名字一样,难以区分。静态工厂方法可以任意命名,提高可读性: ...

2012-03-26 · 2 min · 276 words · -

macOS Basics

macOS Basic # uninstal /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)" # install /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" brew install maven diskutil list 快捷键 截屏: Command + Shift + 3 显示隐藏文件: Command + Shift + . 将光标移动到行首:control + a 将光标移动到行尾:control + e 清除屏幕:control + l 搜索以前使用命令:control + r 清除当前行:control + u 清除至当前行尾:control + k 单词为单位移动:option + 方向键 锁屏 Touch ID:带有 Touch ID 的 MacBook 或妙控键盘,轻按指纹识别键即可瞬间锁屏,比快捷键更快速。 Command (⌘) + Control (⌃) + Q:立即锁定屏幕。 窗口切换 macOS 的设计逻辑:Command + Tab 是在应用程序之间切换,而不是在窗口之间切换。 ...

2026-01-10 · 2 min · 377 words · -

Inotify

Inotify 概述 Inotify 是 Linux 内核提供的一个文件系统事件监控机制,从 Linux 2.6.13 版本开始引入。它允许应用程序监控文件系统的变化,如文件的创建、修改、删除、移动等操作。 核心特性 实时监控:基于事件驱动,当文件系统发生变化时立即通知应用程序 高效性:相比轮询方式,inotify 不需要不断检查文件状态,大大降低了系统开销 灵活性:可以监控单个文件或整个目录树 多事件支持:支持多种文件系统事件类型 工作原理 初始化:应用程序创建一个 inotify 实例(通过 inotify_init() 系统调用),返回一个文件描述符(fd) 添加监控:为需要监控的文件或目录添加 watch(通过 inotify_add_watch()),将 watch 与 inotify 实例关联 事件通知:当被 watch 的文件系统发生变化时,内核会将事件放入该 inotify 实例的事件队列 读取事件:应用程序从 inotify 文件描述符读取事件信息(通过 read() 系统调用) 简单来说: inotify 实例就像一个"邮箱"(用文件描述符标识) 添加 watch 就是告诉内核:“这些文件有变化就往我的邮箱里放消息” 文件变化时,内核自动把事件"投递"到这个邮箱 应用程序通过读取这个文件描述符来"收取邮件"(获取事件) 代码示例: #include <sys/inotify.h> #include <unistd.h> #include <stdio.h> int main() { // 1. 创建 inotify 实例,得到文件描述符 int fd = inotify_init(); // 2. 添加 watch,监控文件的修改事件 int wd = inotify_add_watch(fd, "/path/to/file", IN_MODIFY); // 3. 当文件被修改时,内核会把事件放入 fd 对应的队列 // 4. 应用程序从 fd 读取事件 char buffer[1024]; int length = read(fd, buffer, sizeof(buffer)); // 阻塞等待事件 // 5. 处理事件... struct inotify_event *event = (struct inotify_event *)buffer; printf("文件被修改了!\n"); // 清理 close(fd); return 0; } 关键点: ...

2025-11-19 · 6 min · 1108 words · -

git reset

丢弃单个文件的本地修改 git reset <file> 只能取消暂存(把文件从 staging area 退回工作区),不能丢弃工作区的修改。 要丢弃工作区对某个文件的修改,应使用 git restore: # 丢弃工作区修改,还原为最近一次 commit 的版本 git restore <file> # 等价的旧语法(Git 2.23 之前) git checkout -- <file> # 还原为远程分支的版本(先 fetch 确保远程是最新的) git fetch origin git restore --source=origin/main <file> # 或者用旧语法 git checkout origin/main -- <file> 如果文件已经 git add 进了暂存区,需要先 unstage 再丢弃: # Step 1: 取消暂存(推荐,Git 2.23+) git restore --staged <file> # 旧语法(Git 2.23 之前),效果相同但已不推荐 git reset HEAD <file> # Step 2: 丢弃工作区修改 git restore <file> git restore –staged git restore --staged <file> 是 Git 2.23 引入的新命令,用于取消暂存(unstage),即把文件从暂存区退回工作区,是 git reset HEAD <file> 的现代替代语法。 ...

2026-01-29 · 6 min · 1175 words · -

Git

Git graph LR work["Working tree<br/>工作树/工作区"] stage["Index / Staging Area<br/>暂存区"] repo["Local Repository<br/>本地仓库"] remote["Remote Repository<br/>远程仓库"] discard["✖ discard<br/>丢弃"] work -->|add| stage stage -->|commit| repo repo -->|push| remote remote -->|pull| work remote -->|"fetch/clone"| repo stage -->|checkout| work stage -->|"restore --staged"| work repo -->|merge| work repo -->|"reset --soft"| stage repo -->|rebase| stage repo -->|"reset --mixed"| work repo -->|"reset --hard"| discard 工作区 (working tree) working tree, 2.9.1 之前被称作 Working Directory https://stackoverflow.com/questions/39128500/working-tree-vs-working-directory ...

2026-03-06 · 2 min · 354 words · -

macos apps

macOS Apps 跨平台常用软件统一维护于 my apps,本文只记录 macOS 专属工具。 说明 brew — brew install <name> cask — brew install --cask <name> Essentials 跨平台工具见 my apps,以下为 macOS 专属推荐: app install notes iterm2 cask:iterm2 功能强大的 terminal stats cask:stats 任务栏系统资源监控 itsycal cask:itsycal 任务栏日历(显示周数) tunnelblick cask:tunnelblick OpenVPN GUI 客户端 Productivity app install notes CleanMyMac X — 系统清理(官网购买) Bob cask:bob 翻译/词典 Itsycal cask:itsycal 任务栏日历,显示周数 Stats cask:stats 任务栏 CPU/内存/网络监控 Shottr cask:shottr 截图+标注+OCR,轻量快速 Monosnap cask:monosnap 截图+标注 RealVNC Viewer cask:vnc-viewer 远程桌面 Terminal app install notes iterm2 cask:iterm2 macOS 最流行的 terminal VPN app install notes Tunnelblick cask:tunnelblick OpenVPN GUI,macOS 专属 Graphics / Design app install notes Sketch — 矢量绘图(官网购买) References Homebrew

2026-05-05 · 1 min · 100 words · -