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 · -

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 · -

企业应用架构模式

什么是企业应用架构模式 企业应用架构模式(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 · -