原型模式, 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()); } } } 客户端使用: ...

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

中介者模式, Mediator Pattern

中介者模式(Mediator Pattern)定义一个中介对象来封装一系列对象之间的交互,使各对象不需要显式地相互引用,从而降低耦合度,并可以独立地改变它们之间的交互。 核心思想 当系统中多个对象之间存在复杂的多对多交互时,对象之间的依赖关系会形成网状结构,难以维护。中介者模式将这种网状结构转化为星形结构——所有对象只与中介者通信,由中介者协调各对象之间的交互。 # 不使用中介者:网状结构 A ←→ B A ←→ C B ←→ C B ←→ D ... # 使用中介者:星形结构 A → Mediator ← B ↑ ↓ C D 角色 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()); } } } } 同事类: ...

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

责任链模式, Chain of Responsibility Pattern

责任链模式(Chain of Responsibility)将请求沿着一条处理者链传递,每个处理者决定是否处理该请求,或将其传递给链上的下一个处理者。请求的发送者无需知道最终由哪个处理者来处理,从而实现了发送者与接收者的解耦。 核心思想 不使用责任链时,请求方往往需要硬编码逻辑来判断应该由哪个对象处理,导致紧耦合和大量条件判断。责任链将这些处理者串联起来,请求沿链传递,直到被某个处理者处理(或到达链尾)。 角色 Handler(抽象处理者):定义处理请求的接口,通常包含设置下一个处理者的方法。 ConcreteHandler(具体处理者):实现处理逻辑,决定自己是否处理请求,如果不处理则转发给下一个处理者。 Client(客户端):构建责任链并向链头发起请求。 示例:请假审批 不同级别的请假天数由不同层级的领导审批:组长审批 1 天以内,经理审批 3 天以内,总监审批 7 天以内,超过 7 天不予批准。 抽象处理者: public abstract class Approver { protected Approver next; public Approver setNext(Approver next) { this.next = next; return next; } public abstract void approve(int days); } 具体处理者: public class TeamLeader extends Approver { @Override public void approve(int days) { if (days <= 1) { System.out.println("组长批准了 " + days + " 天假。"); } else if (next != null) { next.approve(days); } } } public class Manager extends Approver { @Override public void approve(int days) { if (days <= 3) { System.out.println("经理批准了 " + days + " 天假。"); } else if (next != null) { next.approve(days); } } } public class Director extends Approver { @Override public void approve(int days) { if (days <= 7) { System.out.println("总监批准了 " + days + " 天假。"); } else { System.out.println("请假 " + days + " 天,超出审批权限,不予批准。"); } } } 客户端构建链并发起请求: ...

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

状态模式, State Pattern

状态模式(State Pattern)允许一个对象在其内部状态发生改变时改变其行为,使该对象看起来像是改变了它的类。 核心思想 在不使用状态模式的情况下,对象的行为往往通过大量 if-else 或 switch 判断当前状态来分支处理,导致代码臃肿、难以扩展。状态模式将每种状态封装成独立的类,对象将行为委托给当前状态对象,状态切换时只需替换状态对象即可。 角色 Context(上下文):持有当前状态的引用,对外暴露行为接口,将行为委托给当前状态对象处理。 State(抽象状态):定义所有具体状态共同的接口。 ConcreteState(具体状态):实现 State 接口,封装该状态下的行为,并在必要时触发状态转换。 示例:交通灯 交通灯有红、黄、绿三种状态,不同状态下的行为不同,且状态之间按规则流转。 抽象状态接口: public interface TrafficLightState { void handle(TrafficLight light); String getColor(); } 具体状态类: public class RedState implements TrafficLightState { @Override public void handle(TrafficLight light) { System.out.println("红灯停。"); light.setState(new GreenState()); } @Override public String getColor() { return "红"; } } public class GreenState implements TrafficLightState { @Override public void handle(TrafficLight light) { System.out.println("绿灯行。"); light.setState(new YellowState()); } @Override public String getColor() { return "绿"; } } public class YellowState implements TrafficLightState { @Override public void handle(TrafficLight light) { System.out.println("黄灯警示,请注意。"); light.setState(new RedState()); } @Override public String getColor() { return "黄"; } } Context(上下文)类: ...

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

策略模式, 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"); } } 算法解决类,提供运行时自由选择和切换算法的能力: ...

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

设计模式 – 模板方法, 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() 方法是可选择实现的逻辑。 ...

2026-04-16 · 3 min · 481 words · -

适配器模式, 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 来复用其接口: ...

2026-04-16 · 1 min · 205 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 接口又包了一层,这有什么意义呢? ...

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

外观模式, Facade Pattern

概念 看到"门面"这个词,大家一定都觉得很熟悉。日常生活中的"门面"就是我们买东西的地方,它跟各种商品的生产商打交道,收集商品后再卖给我们。如果没有"门面",我们将不得不直接跟各种各样的生产商买商品。 Facade 模式正是这样一个"门面":我们本来需要与后台的多个类或接口打交道,而 Facade 模式在客户端和后台之间插入一个中间层——门面,这个门面跟后台的多个类或接口打交道,客户端只需要跟门面打交道即可。 Facade 类是一个简化的用户接口,它和后台中的多个类产生依赖关系,而客户类则只跟 Facade 类产生依赖关系。后台的开发者熟悉自己开发的各个类,容易解决与多个类的依赖关系;而使用者不太熟悉后台的各个类,通过 Facade 可以大大降低使用难度。 情况一:功能分布在多个无关类中 客户类要使用的功能分布在多个类中,客户必须先初始化各个类才能使用。这时适合将这些功能集中在一个 Facade 类里,同时替用户做初始化工作。 场景: 商店里出售三种商品——衣服、电脑和手机,分别由各自的生产厂商提供。 各厂商类: public class CoatFactory { public Coat saleCoat() { // ... return coat; } } public class ComputerFactory { public Computer saleComputer() { // ... return computer; } } public class MobileFactory { public Mobile saleMobile() { // ... return mobile; } } 没有商店时,客户需要分别跟各厂商打交道: ...

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

组合模式, Composite Pattern

概念 组合模式(Composite Pattern)将对象组合成树状层次结构,使客户端对单个对象(叶子节点)和组合对象(容器节点)具有一致的访问方式。 核心思想:部分与整体的统一接口。 角色: Component:抽象组件,定义叶子和容器的公共接口 Leaf:叶子节点,没有子节点,实现具体操作 Composite:容器节点,包含子组件,将操作委托给子节点 示例:文件系统 文件系统是 Composite 模式的经典场景——文件夹可以包含文件或其他文件夹,但对外都提供统一的 getSize() 接口。 // Component public interface FileSystemNode { String getName(); long getSize(); void print(String indent); } // Leaf public class File implements FileSystemNode { private final String name; private final long size; public File(String name, long size) { this.name = name; this.size = size; } @Override public String getName() { return name; } @Override public long getSize() { return size; } @Override public void print(String indent) { System.out.println(indent + "📄 " + name + " (" + size + " bytes)"); } } // Composite public class Directory implements FileSystemNode { private final String name; private final List<FileSystemNode> children = new ArrayList<>(); public Directory(String name) { this.name = name; } public void add(FileSystemNode node) { children.add(node); } public void remove(FileSystemNode node) { children.remove(node); } @Override public String getName() { return name; } @Override public long getSize() { return children.stream() .mapToLong(FileSystemNode::getSize) .sum(); } @Override public void print(String indent) { System.out.println(indent + "📁 " + name + "/"); for (FileSystemNode child : children) { child.print(indent + " "); } } } // Client public class Client { public static void main(String[] args) { Directory root = new Directory("root"); Directory src = new Directory("src"); src.add(new File("Main.java", 1200)); src.add(new File("Utils.java", 800)); Directory resources = new Directory("resources"); resources.add(new File("config.yml", 300)); resources.add(new File("banner.txt", 50)); root.add(src); root.add(resources); root.add(new File("README.md", 500)); root.print(""); System.out.println("Total size: " + root.getSize() + " bytes"); } } 输出: ...

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

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

创建者模式, 建造者模式, Builder 定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 使用场景 多个部件或零件,都可以装配到一个对象中,但产生的结果又不相同时。 当初始化一个对象特别复杂的时候,比如参数多,而且很多参数都有默认值。 它分为抽象建造者 (Builder) 角色、具体建造者 (ConcreteBuilder) 角色、导演者 (Director) 角色、产品 (Product) 角色四个角色。 抽象建造者 (Builder) 角色: 给 出一个抽象接口,以规范产品对象的各个组成成分的建造。 具体建造者 (ConcreteBuilder) 角色: 要完成的任务包括: 1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。 导演者 (Director) 角色: 担任这个角色的类调用具体建造者角色以创建产品对象。 产品 (Product) 角色: 产品便是建造中的复杂对象。 对于Builder模式很简单,但是一直想不明白为什么要这么设计,为什么要向builder要Product而不是向知道建造过程的Director要。刚才google到一篇文章,总算清楚了。在这里转贴一下这位richardluo的比喻。 简单地说,就好象我要装修一套房子,可是我不懂施工——水电怎么走、木作怎么做,每个工种都有自己专注的领域;也不懂整体设计——用什么风格、先做哪道工序、各部分如何协调,这是设计师的职责。于是我需要找一支装修队,各工种各司其职;还得找个设计师,他来规划整体方案、协调各工种按图施工,而设计师本身不动手,只负责下命令。最后,我可以向工人要装修好的房间了。在这个过程中,设计师手里什么都没有,只有图纸和指令,所以要房间也是跟工人要,记住了! 以下是richardluo的代码,我根据他的思路加上了相应的注释。 定义工人接口,即一支装修队所需具备的通用技能。 // 工人接口。水电工负责布线,木工负责木作,油漆工负责涂装。 // 装修完成后,由装修队把房间交还给房主。 public interface Builder { void doElectrical(); // 水电工 void doCarpentry(); // 木工 void doPainting(); // 油漆工 Room getRoom(); } 定义设计师(Director),他持有图纸,协调装修队按方案施工。 // 设计师(Director)。持有图纸,规定施工顺序,但不亲自动手。 public class Designer { public void coordinate(Builder builder) { builder.doElectrical(); builder.doCarpentry(); builder.doPainting(); } } 装修队(ConcreteBuilder),负责具体的施工实施。 // 各专职工人 class ElectricalWorker { public String work() { return "electrical done"; } } class Carpenter { public String work() { return "carpentry done"; } } class Painter { public String work() { return "painting done"; } } // 装修队(ConcreteBuilder)。由水电工、木工、油漆工组成,各司其职。 // 装修完成后,由装修队把房间交还给房主。 public class WorkerTeam implements Builder { private ElectricalWorker electrician = new ElectricalWorker(); private Carpenter carpenter = new Carpenter(); private Painter painter = new Painter(); private String electrical = ""; private String carpentry = ""; private String painting = ""; public void doElectrical() { electrical = electrician.work(); } public void doCarpentry() { carpentry = carpenter.work(); } public void doPainting() { painting = painter.work(); } // 把装修好的房间交还给房主 public Room getRoom() { if (!electrical.equals("") && !carpentry.equals("") && !painting.equals("")) { System.out.println("room ready!"); return new Room(); } else { return null; } } } 房主(Client),雇人、收房。 // 房主。聘请一支装修队和一位设计师,让设计师协调装修队按图施工,最后从装修队手上收房。 public class Client { public static void main(String[] args) { Builder team = new WorkerTeam(); Designer designer = new Designer(); designer.coordinate(team); team.getRoom(); } } 好了,我觉得这样大概能说明白了。不知各位觉得如何呢?或者有更好的应用场景解释,敬请赐教。 ...

2026-04-16 · 4 min · 730 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 ...

2026-01-26 · 3 min · 576 words · -

plantuml, puml

plantuml, puml UML 序列图, Sequence Diagram 用例图, Use Case Diagram 类图, Class Diagram 对象图, Object Diagram 活动图, Activity Diagram 组件图, Component Diagram 部署图, Deployment Diagram 状态图, State Diagram 时序图, Timing Diagram 非 UML 图 架构图, Archimate diagram UML 图 时序图, Sequence Diagram @startuml Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: Another authentication Response Alice ->> Bob: async msg @enduml 类图, Class Diagram @startuml skinparam classFontColor red class Foo note left: parent class Bar Bar : String field0 Bar : String method0() Foo<|--Bar note left: child abstract class Abstract0 Foo--|>Abstract0 interface Interface0 ' 注意, 接口名和冒号之间必须用空格分隔 Interface0 : void method0() class Class0{ - private_field_0 } @enduml @startuml skinparam class { BackgroundColor Lightblue ArrowColor #0ACF97 BorderColor #d5d5d5 } skinparam stereotypeCBackgroundColor YellowGreen Class101 <|.. Class102 @enduml 活动图, Activity Diagram @startuml !theme plain start if (foo?) then (yes) :process0; else (no) :process1; endif stop @enduml 组件图, Component Diagram 别名后面可以标注颜色 修改线和箭头的颜色 文字颜色 语法 # 把组件显示成普通矩形 skinparam componentStyle rectangle # 组件间横向距离 skinparam nodesep 10 # 组件间纵向距离 skinparam ranksep 10 @startuml skinparam componentStyle rectangle skinparam nodesep 10 skinparam ranksep 10 skinparam ParticipantFontColor #A9DCDF ' comments line starts by single quote, 注释 [First component] [Another component] as Comp2 component Comp3 component [Last\ncomponent] as Comp4 [component0] as c0 #ff0000 [<color:#ff0000>component1</color>] as c1 [component2] as c2 [component3] as c3 [component4] as c4 c0 -- c1 c0-[#00ff00]-c2 c1--c3 c0--c3 c2--c4 note left of c0 note0 end note @enduml 部署图, Deployment Diagram @startuml circle 1 circle 2 circle 3 agent 4 1 -- 2 1 -- 3 1 -- 4 queue 5 4 -right- 5 5 -right-2 @enduml 状态图, State Diagram @startuml [*] --> State1 State1 --> [*] State1 : this is a string State1 : this is another string State1 -> State2 State2 --> [*] @enduml 安装 graphviz sudo apt-get install -y graphviz https://graphviz.org/download/ ...

2024-03-19 · 3 min · 620 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 ...

2021-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) ,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现。 ...

2019-10-11 · 2 min · 326 words · -

响应式编程, Reactive Programming, 反应式编程

响应式编程, Reactive Programming, 反应式编程 Reactive Programming 作为观察者模式 (Observer) 的延伸,不同于传统的命令编程方式 ( Imperative programming) 同步拉取数据的方式,如迭代器模式 (Iterator)。而是采用数据发布者同步或异步地推送到数据流 (Data Streams)的方案。当该数据流 (Data Steams)订阅者监听到传播变化时,立即作出响应动作。在实现层面上,Reactive Programming 可结合函数式编程简化面向对象语言语法的臃肿性,屏蔽并发实现的复杂细节,提供数据流的有序操作,从而达到提升代码的可读性,以及减少 Bug 出现的目的。同时,Reactive Programming 结合背压 (Backpressure) 的技术解决发布端生成数据的速率高于订阅端消费的问题。 https://developer.aliyun.com/article/617709 响应式编程为 Java 的企业版应用提供了更高的性能,并降低了内存消耗,主要是通过减少进程的上下文切换来实现的。因为类似的上下文切换对 CPU 和内存的消耗是极大,所以要尽可能的减少这样的切换操作。不过,响应式编程带来的这种性能上的提高,代价是降低了软件的维护性 java 使用一对一的线程模型,一个java线程对应一个内核线程, 高并发情况下 线程上下文切换成为了瓶颈. 而这正是响应式编程的用武之地,它与目前的 Java 线程模型完全相反。目前的线程模型是保证所有的事情都在当前线程执行,但是在响应式编程中,异步是一个准则。一个程序执行过程被认定为一系列异步执行的事件,每个事件都被 Publisher 创建,你不需要关心 Publisher 在哪个线程中创建。在响应式程序里面,程序代码包含了监听和执行异步事件的功能,而且会在必要时提供新的事件。 这个方式在某些场景下很有效果,比如说在程序里面访问外部数据库。传统的企业级 Java 程序里面,系统会发送一段 SQL 语句到数据库上面,阻塞住程序,直到数据库返回查询结果。但是在响应式编程里面,程序会跳过等待结果的过程,正常向下执行代码。当你发送一个 SQL 请求到数据库的时候,会用一个 Pushlisher 来替代阻塞的过程,调用者可以注册这个 Pushlisher,这样的话,在之后数据库返回结果的时候,就会通知 Publisher,然后 Publisher 会通知调用者。 响应式编程的好处就是执行的代码和执行的线程是分开的。因此在操作系统的层面上,上下文切换的代价比较低。 响应式编程也有一些比较严重的问题,写入的代码和执行的代码分离开来,导致阅读和编写代码的难度增加,对于这种异步的代码,编写单元测试和调试代码都很困难。 类似于 C Sharp、JavaScript、Kotlin 等这一类的编程语言在这个领域已经走在了前面,他们在编程语言中集成了这部分功能,可以帮助你执行一小段异步代码,并在返回的时候阻塞,直到执行结束。在 C Sharp 和 JavaScript 中,可以使用 Async 和 Await 关键字,在 Go 和 Kotlin 中,同样包括了协程的概念来提供类似的功能。 ...

2019-05-10 · 1 min · 119 words · -

舱壁模式

舱壁模式 什么是舱壁模式 舱壁模式 (Bulkhead) 隔离了每个工作负载或服务的关键资源,如连接池、内存和CPU。 使用舱壁避免了单个工作负载 (或服务) 消耗掉所有资源,从而导致其他服务出现故障的场景。 这种模式主要是通过防止由一个服务引起的级联故障来增加系统的弹性。 工业中使用舱壁将船舶划分为几个部分,以便在船体破坏的情况下,可以将船舶各个部件密封起来。舱壁的概念在软件开发中可以被应用在隔离资源上。通过应用舱壁模式,我们可以保护有限的资源不被耗尽。例如,对于一个有连接数限制的数据库实例来说,如果我们有两种连接它的操作,我们采用可以采用两个连接池的方式进行连接,来代替仅采用一个共享连接池的方式。由于这种客户端与资源进行了隔离,超时或过度使用池的操作页不会使其他操作失败。泰坦尼克号沉没的主要原因之一是其舱壁设计失败,水可以通过上面的甲板倒在舱壁的顶部,导致整个船体淹没。 作者: AskHarries 链接: https://juejin.im/post/5b32d3e36fb9a00e952ce899 来源: 掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2019-04-28 · 1 min · 17 words · -

设计模式, Design Pattern, Front Controller Pattern

设计模式, Design Pattern, Front Controller Pattern http://www.cnblogs.com/TonyYPZhang/p/5516192.html Front Controller Pattern, 即前端控制器模式,用于集中化用户请求,使得所有请求都经过同一个前端控制器处理,处理内容有身份验证、权限验证、记录和追踪请求等,处理后再交由分发器把请求分发到对于的处理者。 前端控制器模式主要涉及下面三个角色 前端控制器(Front Controller) - 一个处理器用于处理全部的用户请求 分发器(Dispatcher) - 把处理后的请求分发到对于的业务处理程序 视图(View) - 真正处理请求业务程序 下面是前端控制器的一个简单案例。 HomeView, StudentView 分别是具体业务处理程序。Dispatcher 用于把请求分发到对于的 View 中。FrontController 是所有用户请求的入口,进行身份验证、权限验证、记录或追踪请求日志。FrontControllerDemo 演示前端控制器模式。 代码实现 HomeView, StudentView 提供真正的业务处理逻辑 public class HomeView { public void show(){ System.out.println(“show Home view “); } } public class StudentView { public void show(){ System.out.println(“show student view “); } } Dispatcher 分发用户的请求到对应业务处理程序 public class Dispatcher { private StudentView studentView; private HomeView homeView; public Dispatcher(){ homeView = new HomeView(); ...

2017-02-12 · 1 min · 170 words · -

设计模式 – State/状态模式

设计模式 – State/状态模式 State模式的定义: 不同的状态,不同的行为;或者说,每个状态有着相应的行为. 何时使用? State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了. 不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State. 是否使用? 在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度. 这里要阐述的是"开关切换状态" 和" 一般的状态判断"是有一些区别的, " 一般的状态判断"也是有 if..elseif结构,例如: if (which==1) state=“hello”; else if (which==2) state=“hi”; else if (which==3) state=“bye”; 这是一个 " 一般的状态判断",state值的不同是根据which变量来决定的,which和state没有关系.如果改成: if (state.euqals(“bye”)) state=“hello”; else if (state.euqals(“hello”)) state=“hi”; else if (state.euqals(“hi”)) state=“bye”; 这就是 “开关切换状态”,是将state的状态从"hello"切换到"hi",再切换到"“bye”;在切换到"hello",好象一个旋转开关,这种状态改变就可以使用State模式了. 如果单纯有上面一种将"hello"->“hi”->“bye”->“hello"这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了. 请看下例: import java.awt.*; public class OldContext { private Color state = null; public void push() { //如果当前red状态 就切换到blue if (state == Color.red) state = Color.blue; //如果当前blue状态 就切换到green else if (state == Color.blue) state = Color.green; //如果当前black状态 就切换到red else if (state == Color.black) state = Color.red; //如果当前green状态 就切换到black else if (state == Color.green) state = Color.black; Sample sample = new Sample(state); sample.operate(); } public void pull() { //与push状态切换正好相反 if (state == Color.green) state = Color.blue; else if (state == Color.black) state = Color.green; else if (state == Color.blue) state = Color.red; else if (state == Color.red) state = Color.black; Sample sample2 = new Sample(state); sample2.operate(); } } 在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它. ...

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

系统架构图

系统架构图 系统架构图怎么画?系统架构图首先是人,人是构成系统架构图的核心,也就是系统架构师。IBM工程师的说明是: 架构师的主要责任是提供开发人员和项目经理之间的共用沟通媒体。他们负责让业务规则及需求与工程实践及限制相适应,以确保成功。 中文Wiki上的说明是: 系统架构师负责设计系统整体架构,从需求到设计的每个细节都要考虑到,把握整个项目,使设计的项目尽量效率高,开发容易,维护方便,升级简单。这两个部分加起来组成了系统架构师的定义。本文主要介绍系统架构图怎么画? 系统架构图怎么画?要画好系统架构图,首先明白系统架构图都有哪些,你要画的系统架构图属于?这是系统架构师工作内容与职责之基础。 http://chasefull.blog.51cto.com/6570525/1134536 http://blog.itpub.net/6517/viewspace-609654

2015-06-09 · 1 min · 8 words · -