外观模式, Facade Pattern

外观模式, Facade Pattern 看到"门面"这个词,大家一定都觉得很熟悉。日常生活中的"门面"就是我们买东西的地方,它跟各种商品的生产商打交道,收集商品后再卖给我们。如果没有"门面",我们将不得不直接跟各种各样的生产商买商品。 Facade 模式正是这样一个"门面":我们本来需要与后台的多个类或接口打交道,而 Facade 模式在客户端和后台之间插入一个中间层——门面,这个门面跟后台的多个类或接口打交道,客户端只需要跟门面打交道即可。 Facade 类是一个简化的用户接口,它和后台中的多个类产生依赖关系,而客户类则只跟 Facade 类产生依赖关系。后台的开发者熟悉自己开发的各个类,容易解决与多个类的依赖关系;而使用者不太熟悉后台的各个类,通过 Facade 可以大大降低使用难度。 示例:电商下单流程 classDiagram class Client class OrderFacade { +placeOrder(userId, productId, amount) } class InventoryService { +checkStock(productId) } class PaymentService { +charge(userId, amount) } class OrderService { +createOrder(userId, productId) } class NotificationService { +sendConfirmation(userId) } Client --> OrderFacade OrderFacade --> InventoryService OrderFacade --> PaymentService OrderFacade --> OrderService OrderFacade --> NotificationService 完成一次下单需要依次调用库存服务、支付服务、订单服务和通知服务。没有 Facade 时,调用方必须自己了解并编排这四个步骤: // 调用方需要知道正确的调用顺序,且任何地方下单都要重复这段逻辑 inventoryService.checkStock(productId); paymentService.charge(userId, amount); orderService.createOrder(userId, productId); notificationService.sendConfirmation(userId); 引入 OrderFacade,将编排逻辑封装在内部: ...

Created 16166-04-16 · Updated 17176-05-17 · 1 min · 152 words · -

组合模式, Composite Pattern

Composite Pattern, 组合模式 组合模式(Composite Pattern)将对象组合成树状层次结构,使客户端对单个对象(叶子节点)和组合对象(容器节点)具有一致的访问方式。 核心思想:部分与整体的统一接口。 角色: Component:抽象组件,定义叶子和容器的公共接口 Leaf:叶子节点,没有子节点,实现具体操作 Composite:容器节点,包含子组件,将操作委托给子节点 UML 类图 classDiagram class FileSystemNode { <> +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() 接口。 ...

Created 16166-04-16 · Updated 16166-05-16 · 2 min · 363 words · -

代理模式, 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 接口又包了一层,这有什么意义呢? ...

Created 16166-04-16 · Updated 15156-05-15 · 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{} 命令。 ...

Created 16166-04-16 · Updated 15156-05-15 · 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 更通用:特殊对象可以有具体的默认行为,甚至代表一个有意义的领域概念(如"匿名用户"“未知账户"“空购物车”)。 ...

Created 15156-05-15 · Updated 15156-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); } 具体中介者: import java.util.ArrayList; import java.util.List; public class ChatRoomImpl implements ChatRoom { private final List<User> users = new ArrayList<>(); @Override public void addUser(User user) { users.add(user); } @Override public void sendMessage(String message, User sender) { for (User user : users) { if (user != sender) { user.receive(message, sender.getName()); } } } } 同事类: ...

Created 16166-04-16 · Updated 15156-05-15 · 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) “书。 ...

Created 29296-10-29 · Updated 15156-05-15 · 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 的内部实现(容器负责构建,这里展示其原理): ...

Created 16166-04-16 · Updated 15156-05-15 · 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 模式重构。 ...

Created 23236-01-23 · Updated 15156-05-15 · 2 min · 358 words · -

POSA1 架构模式

POSA1 是什么 《Pattern-Oriented Software Architecture, Volume 1: A System of Patterns》(简称 POSA1),1996 年出版,作者为 Frank Buschmann、Regine Meunier、Hans Rohnert、Peter Sommerlad、Michael Stal。 POSA1 关注的是架构模式(Architectural Patterns),粒度比 GoF(1994)的 23 种设计模式更大——GoF 解决的是类与对象之间如何协作,POSA1 解决的是整个系统应该如何组织。 GoF(1994) POSA1(1996) 模式级别 对象/类设计 系统/架构 典型模式 Strategy、Observer、Chain of Responsibility Pipes & Filters、Layers、Broker 解决问题 类之间如何协作 整个系统如何组织 POSA1 中的主要模式 Layers(分层) 将系统分解为若干层,每层只依赖下层,对上层屏蔽实现细节。典型实现:OSI 网络模型、TCP/IP 协议栈、三层架构(表现层 / 业务层 / 数据层)。 Pipes and Filters(管道-过滤器) 将数据处理拆分为一系列独立的 Filter,每个 Filter 负责单一转换,通过 Pipe 传递数据。整个系统是可组合的处理管道。 特征: 每个 Filter 独立,不依赖其他 Filter 的内部状态 Filter 可以任意组合、复用、替换 任何一个 Filter 可以短路,中断后续处理 经典实现: ...

Created 12126-05-12 · Updated 12126-05-12 · 1 min · 141 words · -

Front Controller Pattern

概述 Front Controller Pattern(前端控制器模式)来自 Martin Fowler 的《企业应用架构模式》(Patterns of Enterprise Application Architecture,2002),属于 Web 层架构模式,不是 GoF 23 种设计模式的一部分。 详见 企业应用架构模式。 解决的问题 在原始 Servlet 时代,每个 URL 对应一个独立的 Servlet 类,这是 Page Controller 模式: /users → UsersServlet /orders → OrdersServlet /products → ProductsServlet 每个 Servlet 都要自己处理身份验证、日志记录、权限检查,代码大量重复。随着 URL 增多,web.xml 里的注册条目也膨胀。 Front Controller 的解法是单一入口: 所有请求 → FrontController(统一处理横切关注点)→ Dispatcher → 具体处理器 三个角色 Front Controller:所有请求的唯一入口,集中处理身份验证、权限验证、日志追踪等横切关注点 Dispatcher:将请求路由到对应的具体处理器(View/Handler) View / Handler:真正处理业务逻辑的模块 Spring MVC 中的实现 Spring MVC 的 DispatcherServlet 是 Front Controller 模式的标准实现: ...

Created 12126-02-12 · Updated 11116-05-11 · 2 min · 234 words · -

企业应用架构模式

什么是企业应用架构模式 企业应用架构模式(Patterns of Enterprise Application Architecture,简称 PoEAA) 由 Martin Fowler 在 2002 年出版的同名书中系统整理,专门解决企业级应用中反复出现的架构问题。 它与 GoF 23 种设计模式的区别: GoF 设计模式(1994) 企业应用架构模式(2002) 关注层面 对象级别,类与类之间的协作 应用架构级别,层与层之间的设计 典型问题 如何创建对象、如何解耦行为 如何组织 Web 层、如何访问数据库、如何处理并发 典型模式 Factory、Observer、Strategy Front Controller、Repository、Unit of Work 两套模式不冲突,可以同时使用。 Web 表现层模式 Front Controller(前端控制器) 所有 HTTP 请求通过单一入口,集中处理身份验证、日志、权限等横切关注点,再路由到具体处理器。 所有请求 → Front Controller → Dispatcher → 具体 Handler Spring MVC 实现:DispatcherServlet 是标准的 Front Controller 实现,映射到 / 接收所有请求,通过 HandlerMapping 路由到对应的 @Controller 方法。 详见 Front Controller Pattern。 Page Controller(页面控制器) 每个页面或 URL 对应一个独立的控制器类。原始 Servlet 就是这种模式——/users 对应 UsersServlet,/orders 对应 OrdersServlet。 ...

Created 11116-05-11 · Updated 11116-05-11 · 1 min · 190 words · -

Command Dispatcher / Command Bus

Command Dispatcher(命令分发器)和 Command Bus(命令总线)是架构模式,属于应用层架构设计的范畴,不在 GoF 23 种设计模式之列。 注意:“Command Dispatcher” 是开发者社区的口语化称呼,没有权威模式书籍正式定义。对应的正式模式名是 EIP(企业集成模式)中的 Content-Based Router(见下文)。 两者不是同一个模式,Command Bus 是在 Content-Based Router 基础上增加了中间件管道的演化版本,核心差异在于中间件管道。 Command Dispatcher Command Bus 核心机制 ID → Handler 直接路由 ID → 中间件链 → Handler 中间件支持 无 有(日志、验证、事务等) 复杂度 简单 较复杂 典型场景 IoT 协议解析、游戏指令 CQRS、DDD 应用层 Command Dispatcher 核心结构: 收到消息 → 解析 ID → registry.get(id) → handler.Handle(data) 服务初始化时将每种指令的处理类注册到一个 Map。运行时收到消息后,解析出消息类型 ID,从注册表查找对应处理器并直接调用。 // Handler 接口,每种指令实现一个 type Handler interface { Handle(data []byte) error } // Dispatcher 维护 id -> handler 的注册表 type Dispatcher struct { handlers map[uint8]Handler } func NewDispatcher() *Dispatcher { return &Dispatcher{handlers: make(map[uint8]Handler)} } func (d *Dispatcher) Register(id uint8, h Handler) { d.handlers[id] = h } func (d *Dispatcher) Dispatch(id uint8, data []byte) error { h, ok := d.handlers[id] if !ok { return fmt.Errorf("unknown command id: 0x%02X", id) } return h.Handle(data) } // --- 具体指令处理类 --- type LoginHandler struct{} func (h *LoginHandler) Handle(data []byte) error { fmt.Printf("处理登录指令: %x\n", data) return nil } type LocationReportHandler struct{} func (h *LocationReportHandler) Handle(data []byte) error { fmt.Printf("处理位置上报: %x\n", data) return nil } // --- 初始化注册 --- func main() { d := NewDispatcher() d.Register(0x01, &LoginHandler{}) d.Register(0x02, &LocationReportHandler{}) // 收到一条原始消息,解析出 id=0x02 d.Dispatch(0x02, []byte{0x01, 0x02, 0x03}) } Command Bus 在 Dispatcher 的基础上增加了中间件管道,每条命令在到达 Handler 之前会依次经过所有中间件。 ...

Created 28286-04-28 · Updated 28286-04-28 · 3 min · 574 words · -

原型模式, Prototype Pattern

原型模式, Prototype Pattern 原型模式(Prototype Pattern)是一种创建型模式,通过复制(克隆)一个已有对象来创建新对象,而不是通过 new 重新实例化。 核心思想 当创建一个对象的代价较大(如需要复杂初始化、数据库查询、网络请求等)时,可以先创建一个原型对象,后续通过克隆该原型来快速获得新对象。 角色 Prototype(抽象原型):声明克隆方法 clone()。 ConcretePrototype(具体原型):实现克隆方法,返回自身的副本。 Client(客户端):通过调用原型的克隆方法来创建新对象。 浅克隆与深克隆 浅克隆(Shallow Clone) 深克隆(Deep Clone) 基本类型字段 复制值 复制值 引用类型字段 复制引用(共享对象) 递归复制,独立对象 修改互不影响 ❌ 引用字段会互相影响 ✅ 完全独立 示例:细胞克隆 Java 通过实现 Cloneable 接口来支持浅克隆: public class Cell implements Cloneable { private String cellWall; // 细胞壁 private String cellMembrane; // 细胞膜 private String cellularTissue; // 细胞组织 public String getCellWall() { return cellWall; } public void setCellWall(String cellWall) { this.cellWall = cellWall; } // 其他 getter/setter 省略 @Override public Cell clone() { try { return (Cell) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(e.getMessage()); } } } 客户端使用: ...

Created 16166-04-16 · Updated 16166-04-16 · 1 min · 195 words · -

策略模式, Strategy Pattern

策略模式, Strategy Pattern 策略模式(Strategy Pattern)定义了一系列算法,把这些算法一个个封装成单独的类,使它们可以相互替换,且算法的改变不会影响使用算法的客户。 策略模式重点是封装不同的算法和行为,不同的场景下可以相互替换。策略模式是开闭原则的体现——对扩展开放,对修改关闭:新增策略时不影响其他类,且场景类只依赖抽象而不依赖具体实现。 示例:字符串替换策略 这里以字符串替换为例:读取一个文件后,需要替换其中的变量再输出。替换方式可能有多种,我们用策略模式来支持运行时切换。 首先,建立抽象策略类 RepTempRule,定义公用变量和方法: public abstract class RepTempRule { protected String oldString = ""; public void setOldString(String oldString) { this.oldString = oldString; } protected String newString = ""; public String getNewString() { return newString; } public abstract void replace() throws Exception; } 现在有两个具体策略:将文本中的 aaa 替换成 bbbb,或替换成 ccc: public class RepTempRuleOne extends RepTempRule { @Override public void replace() throws Exception { newString = oldString.replaceFirst("aaa", "bbbb"); System.out.println("this is replace one"); } } public class RepTempRuleTwo extends RepTempRule { @Override public void replace() throws Exception { newString = oldString.replaceFirst("aaa", "ccc"); System.out.println("this is replace two"); } } 算法解决类,提供运行时自由选择和切换算法的能力: ...

Created 16166-04-16 · Updated 16166-04-16 · 1 min · 213 words · -

设计模式 – 模板方法, Template Method

模板方法, Template Method 模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。 模式结构 模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。 模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。 模板方法所代表的行为称为顶级行为,其逻辑称为顶级逻辑。 这里涉及到两个角色: 抽象模板(Abstract Template) 角色的责任: 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。 定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。 具体模板(Concrete Template) 角色的责任: 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。 每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。 基础示例 抽象模板角色类,abstractMethod()、hookMethod() 等基本方法是顶级逻辑的组成步骤,这个顶级逻辑由 templateMethod() 方法代表。 public abstract class AbstractTemplate { /** * 模板方法 */ public void templateMethod() { // 调用基本方法 abstractMethod(); hookMethod(); concreteMethod(); } /** * 基本方法的声明(由子类实现) */ protected abstract void abstractMethod(); /** * 基本方法(空方法) */ protected void hookMethod() {} /** * 基本方法(已经实现) */ private final void concreteMethod() { // 业务相关的代码 } } 具体模板角色类实现了父类所声明的基本方法,abstractMethod() 方法所代表的就是强制子类实现的剩余逻辑,而 hookMethod() 方法是可选择实现的逻辑。 ...

Created 16166-04-16 · Updated 16166-04-16 · 3 min · 484 words · -

适配器模式, Adapter Pattern

适配器模式, Adapter Pattern 通常,客户类通过类的接口访问它提供的服务。有时,现有的类可以提供客户类需要的功能,但它所提供的接口不一定是客户类所期望的——可能接口过于详细、缺少细节,或者名称不匹配。 在这种情况下,需要将现有接口转化为客户类期望的接口,从而保证对现有类的重用。适配器模式(Adapter Pattern)通过定义一个包装类来完成这种转化: Target:客户类期望的接口 Adaptee:现有的、接口不兼容的类 Adapter:包装 Adaptee,实现 Target 接口 当客户类调用 Adapter 的方法时,Adapter 内部转而调用 Adaptee 的对应方法,这个过程对客户类透明。 类适配器 vs 对象适配器 类适配器 对象适配器 实现方式 继承 Adaptee 组合 Adaptee 灵活性 静态绑定,无法适配 Adaptee 子类 可适配 Adaptee 及其所有子类 方法重载 可重载 Adaptee 的方法 不能直接重载,但可在包装方法中修改行为 可见性 客户类可见 Adaptee 的 public 方法 客户类与 Adaptee 完全解耦 Java 限制 仅适用于 Target 是接口(Java 单继承) Target 可以是接口或抽象类 类适配器示例 Adapter 通过继承 Adaptee 来复用其接口: // Target:客户类期望的接口 public interface Target { void sampleOperation1(); } // Adaptee:现有的第三方类,接口不兼容 public class Adaptee { public void sampleOperation2() { System.out.println("Adaptee.sampleOperation2()"); } } // Adapter:继承 Adaptee,实现 Target public class Adapter extends Adaptee implements Target { @Override public void sampleOperation1() { this.sampleOperation2(); } } // Client public class Client { public static void main(String[] args) { Target target = new Adapter(); target.sampleOperation1(); } } 对象适配器示例 Adapter 通过组合 Adaptee 来复用其接口: ...

Created 16166-04-16 · Updated 16166-04-16 · 1 min · 207 words · -

DDD

DDD 领域驱动设计 (Domain-Driven Design,简称 DDD) Domain Layer 领域层 - 业务实体, 值对象, 领域服务 Infrastructure Layer 基础设施层 - 数据访问, 外部服务调用等技术实现 Application Layer 应用层 - 协调领域对象来执行应用用例 Interface Layer 接口层 - API 控制器, 视图 值对象 (Value Objects) 实体对象 (Entity) Repository 模式 - 抽象的数据访问层 聚合根 Factory 模式 Domain Service 值对象 (Value Objects) 代表领域中没有身份标识但有重要意义的概念 不可变性 (Immutability), 一旦创建,不能修改, 只读属性 基于值的相等性 (Value-based Equality), 比较的是值,不是对象引用 无身份标识 (No Identity), 两个值相同的对象被认为是相等的 可哈希性 (Hashable) 生命周期 短暂,可替换 封装业务逻辑: 比如某些固定规则的字符串组合 值对象的使用场景: 复合标识符 实体对象 (Entity) 有唯一身份ID ...

Created 26266-01-26 · Updated 26266-01-26 · 3 min · 576 words · -

Reactor, Dispatcher 模式

Reactor / Dispatcher 模式 了解 Reactor 模式,就要先从事件驱动的开发方式说起。 我们知道,服务器开发,CPU 的处理速度远高于 IO 速度,为了避免 CPU 因为 IO 而阻塞,好一点的方法是多进程或线程处理,但这会带来一些进程切换的开销。 这时先驱者找到了事件驱动,或者叫回调的方法。这种方式就是,应用向一个中间人注册一个回调 (Event handler),当 IO 就绪后,这个中间人产生一个事件,并通知此 handler 进行处理。这种回调的方式,也实现了"好莱坞原则" - “Don’t call us, we’ll call you.” 那在 IO 就绪这个事件后,谁来充当这个中间人?Reactor 模式的答案是: 有一个不断等待和循环的单独进程 (线程) 来做这件事,它接受所有 handler 的注册,并负责向操作系统查询 IO 是否就绪,在就绪后用指定的 handler 进行处理,这个角色的名称就叫做 Reactor。 事件驱动, 回调函数, reactor, 响应式编程 事件驱动是概念,回调函数是实现方式。不用回调函数,也可以实现事件驱动。例如:把事件消息发送到队列,另外一个进程取队列处理即可 (没有回调函数)。事件驱动的本质特征:中心轮询机制。event loop的loop是轮询。轮询的目的是什么?感知!对象发生变化,如何感知这种变化?不断的循环查询,loop探测!系统n个对象,每个对象一个for循环 探测彼此的变化?nonono……建立一个轮询中心,这个轮询中心去轮询每个对象,这就是事件驱动。发生了变化,通知感兴趣的对象,怎么处理?就是定义一个回调函数。事件驱动,属于“感知层”的概念;轮询中心,往往就是操作系统本身;对于浏览器而言,就是浏览器本身。也就是系统是轮询中心,你定义 函数,系统调用你定义的函数。对比:系统定义api,你调用api。谁定义函数,谁调用,角色颠倒了!api:系统定义的函数,你去调用; 事件驱动:你定义的回调函数,被系统调用。还是没有懂?事件驱动,就是“哨兵模式”!哨兵轮询环境信息,你就安心睡大觉好了,不用每个人都轮询环境。发生了事件,哨兵 (操作系统/浏览器/轮询中心)负责通知你!怎么处理这个消息,是你的责任! 作者:fdego 链接:https://www.zhihu.com/question/30396023/answer/447966119 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 事件驱动, reactor The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. https://en.wikipedia.org/wiki/Reactor_pattern ...

Created 11116-07-11 · Updated 11116-07-11 · 3 min · 621 words · -

架构, 架构师, architecture

架构, 架构师, architecture 架构师: architect 架构: architecture 软件架构 软件架构 (software architecture) 就是软件的基本结构。 分层架构 分层架构 (layered architecture) 是最常见的软件架构,也是事实上的标准架构。如果你不知道要用什么架构,那就用它。 这种架构将软件分成若干个水平层,每一层都有清晰的角色和分工,不需要知道其他层的细节。层与层之间通过接口通信。 虽然没有明确约定,软件一定要分成多少层,但是四层的结构最常见。 表现层 (presentation) : 用户界面,负责视觉和用户互动 业务层 (business) : 实现业务逻辑 持久层 (persistence) : 提供数据,SQL 语句就放在这一层 数据库 (database) : 保存数据 有的软件在逻辑层和持久层之间,加了一个服务层 (service) ,提供不同业务逻辑需要的一些通用接口。 用户的请求将依次通过这四层的处理,不能跳过其中任何一层。 事件驱动架构 事件 (event) 是状态发生变化时,软件发出的通知。 事件驱动架构 (event-driven architecture) 就是通过事件进行通信的软件架构。它分成四个部分。 事件队列 (event queue) : 接收事件的入口 分发器 (event mediator) : 将不同的事件分发到不同的业务逻辑单元 事件通道 (event channel) : 分发器与处理器之间的联系渠道 事件处理器 (event processor) : 实现业务逻辑,处理完成后会发出事件,触发下一步操作 微核架构 微核架构 (microkernel architecture) 又称为"插件架构" (plug-in architecture) ,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现。 ...

Created 11116-10-11 · Updated 11116-10-11 · 2 min · 326 words · -