当前位置: 首页 > news >正文

设计模式笔记

声明 : 未整理完成,仅仅记录下

快速回忆

  • 结构型 : 适桥组装外享代
类型设计模式英文key(理解的关键点)
创建型单例Singleton Pattern-
工厂方法Factory Method Pattern
抽象工厂Abstract Factory Pattern
建造者Builder Patternappend() / 构造字符串
原型Prototype Patternclone / 拷贝构造
结构型适配器Adapter Pattern改变接口
桥接器Bridge PatternJDBC驱动接口
组合Composite Pattern
装饰器Decorator Pattern包装成一个子对象(不改变接口)
外观Facade Pattern子系统对外的统一入口
享元Flyweight PatternJAVA中字符串常量池
代理Proxy PatternSpring AOP
行为型责任链Chain of Responsibility PatternServlet中的FilterChain
命令Command Pattern
解释器Interpreter Pattern
迭代器Iterator Pattern
中介者Mediator Pattern一个中介对象来封装一系列对象之间的交互,(一个系统内的)多个对象间通过中介交互
备忘录Memento Pattern
观察者Observer Pattern(观察者)订阅
状态模式State Pattern
策略Strategy Pattern策略替换
模板方法Template Method Patternservelet重写doGet和doPost
访问者Visitor PatternDouble Dispatch

混淆区分

个别难理解的

1. 访问者模式

想象一个场景:你是一家公司的CEO,你的公司有两个稳定的部门:工程师部 (Engineer) 和经理部 (Manager)。这就是你的“对象结构”,它很稳定,不常变化。

现在,你想让不同的“外部人员”来访问你的公司,并对不同部门的人做不同的事:

一位访客是财务总监 (CFOVisitor):他来找工程师核算工资,找经理审批预算。

另一位访客是CTO (CTOVisitor):他来找工程师review代码,找经理制定技术路线。

如果不使用访问者模式,代码会怎样?

你可能会在 Engineer 和 Manager 类里不停地加方法:calculateSalary(), reviewCode(), approveBudget()… 每来一个新访客,你就要修改所有部门的类!这违反了“对修改关闭,对扩展开放”的原则。

访问者模式的核心思想就是:
允许你在不修改现有部门(元素)类的情况下,为它们定义新的操作(访客)。

它将数据结构(公司部门)和数据操作(访客要做的事)清晰地分离开。

代码模拟:一步步实现访问者模式
让我们用代码来演绎上面这个例子。

第1步:定义“元素”接口 - 公司员工
所有可以被访问的“部门”都必须实现这个接口。它只有一个核心方法 accept(Visitor visitor)。

// 元素接口:声明了一个接受访问者的方法
public interface Employee {void accept(Visitor visitor); // 每个员工都“接受”一个访客
}

第2步:实现具体的“元素” - 具体部门

// 具体元素:工程师
public class Engineer implements Employee {private String name;private double salary;public Engineer(String name, double salary) {this.name = name;this.salary = salary;}// 最重要的方法!这里实现了“双分派”@Overridepublic void accept(Visitor visitor) {// 1. 第一步:根据`this`,确定自己是`Engineer`类型。// 2. 第二步:调用访问者的`visit(this)`方法,把自己的具体类型(`Engineer`)传递过去。visitor.visit(this);}// 工程师特有的方法,比如写代码public void code() {System.out.println(name + " is coding...");}public double getSalary() { return salary; }
}// 具体元素:经理
public class Manager implements Employee {private String name;private double budget;public Manager(String name, double budget) {this.name = name;this.budget = budget;}@Overridepublic void accept(Visitor visitor) {// 同样,把`Manager`这个具体类型传递过去visitor.visit(this);}// 经理特有的方法,比如开会public void meeting() {System.out.println(name + " is in a meeting...");}public double getBudget() { return budget; }
}

第3步:定义“访问者”接口
为每一种“元素”都声明一个访问方法。这样,一个新的访问者就必须知道如何对待所有类型的员工。

// 访问者接口:为每种元素都声明一个访问方法
public interface Visitor {void visit(Engineer engineer); // 重载方法void visit(Manager manager);   // 重载方法
}

第4步:实现具体的“访问者” - 具体访客
这才是模式威力的体现!添加新操作变得无比简单。

// 具体访问者:财务总监(负责核算工资和预算)
public class CFOVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {// 财务总监面对工程师:核算工资double salary = engineer.getSalary();System.out.println("Engineer " + engineer.name + "'s salary is: $" + salary);}@Overridepublic void visit(Manager manager) {// 财务总监面对经理:审批预算double budget = manager.getBudget();System.out.println("Manager " + manager.name + "'s budget is: $" + budget);}
}// 具体访问者:CTO(负责技术工作)
public class CTOVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {// CTO面对工程师:Review代码System.out.println("CTO is reviewing " + engineer.name + "'s code.");engineer.code(); // 可以让工程师演示一下}@Overridepublic void visit(Manager manager) {// CTO面对经理:讨论技术路线System.out.println("CTO is discussing tech roadmap with Manager " + manager.name);manager.meeting();}
}

第5步:客户端使用
现在,我们可以看到访问者模式是如何工作的:

public class CompanyReport {public static void main(String[] args) {// 1. 创建公司员工(稳定的数据结构)List<Employee> employees = Arrays.asList(new Engineer("Alice", 120000),new Manager("Bob", 500000),new Engineer("Charlie", 110000));// 2. 创建不同的访问者(易变的操作)Visitor cfo = new CFOVisitor();Visitor cto = new CTOVisitor();System.out.println("=== CFO's Visit ===");// 3. 让每个员工接受CFO的访问for (Employee employee : employees) {employee.accept(cfo); // 关键行!}System.out.println("\n=== CTO's Visit ===");// 4. 让每个员工接受CTO的访问for (Employee employee : employees) {employee.accept(cto); // 关键行!}}
}
  • 输出结果:
text
=== CFO's Visit ===
Engineer Alice's salary is: $120000.0
Manager Bob's budget is: $500000.0
Engineer Charlie's salary is: $110000.0=== CTO's Visit ===
CTO is reviewing Alice's code.
Alice is coding...
CTO is discussing tech roadmap with Manager Bob
Bob is in a meeting...
CTO is reviewing Charlie's code.
Charlie is coding...
  • 核心机制:“双分派” (Double Dispatch)
  • 这是理解访问者模式的关键。在上面的代码中,最关键的一行是:
employee.accept(visitor);

这行代码完成了两次动态分配(分派):

  1. 第一次分派(根据 employee 的实际类型):employee 可能是 Engineer 或 Manager。JVM在运行时才能确定它的具体类型,从而决定调用 Engineer.accept() 还是 Manager.accept()。

  2. 第二次分派(根据 visitor 的实际类型):在 accept 方法内部,会调用 visitor.visit(this)。这里的 this 是非常明确的(例如,在 Engineer.accept() 里,this 就是 Engineer 类型)。JVM此时又能根据 visitor 的具体类型(是 CFOVisitor 还是 CTOVisitor)和 visit 方法的参数类型(Engineer),决定最终调用 CFOVisitor.visit(Engineer e) 还是 CTOVisitor.visit(Engineer e)。

通过这两步,最终将“操作”绑定到了“具体的元素类型”和“具体的访问者类型”上。 这就是“双分派”。

http://www.dtcms.com/a/344250.html

相关文章:

  • 开题报告被退回?用《基于大数据的慢性肾病数据可视化分析系统》的Hadoop技术,一次通过不是梦
  • Matplotlib 可视化大师系列(五):plt.pie() - 展示组成部分的饼图
  • 故障诊断:基于大模型的实现方法与开源实践(从入门到精通)
  • Matplotlib 可视化大师系列(一):plt.plot() - 绘制折线图的利刃
  • linux----进度条实现和gcc编译
  • [MySQL数据库] MySQL优化策略
  • imx6ull-驱动开发篇35——设备树下的 platform 驱动实验
  • 【渗透测试】SQLmap实战:一键获取MySQL数据库权限
  • 如何在 Axios 中处理多个 baseURL 而不造成混乱
  • 用过redis哪些数据类型?Redis String 类型的底层实现是什么?
  • 【Java后端】 Spring Boot 集成 Redis 全攻略
  • java视频播放网站
  • 正点原子【第四期】Linux之驱动开发学习笔记-2.1LED灯驱动实验(直接操作寄存器)
  • 分布式与微服务
  • 20250822在Ubuntu24.04.2下指定以太网卡的IP地址
  • 深度学习入门详解:从神经网络到实践应用
  • 【English】复合句中的先行词在从句中是否充当成分
  • 吉利汽车与芯鼎微成立联合创新实验室共谱车规级LCoS显示新篇章
  • 面向RF设计人员的微带贴片天线计算器
  • Gamma校正硬件设计实现
  • Elasticsearch搜索原理
  • 加密狗如何抵御各类破解与攻击?深度解析加密狗多层保护机制
  • 关于数据产业规模测算的认识与思考
  • Paddle3D-PETRv1 精度测试与推理实践指南
  • JavaSSM框架从入门到精通!第三天(MyBatis(二))!
  • C++ OpenGL中几个常见库及其区别
  • 轮廓检测技术不仅能精确计算图像中的轮廓数量,还能完整记录每个轮廓包含的所有像素点坐标
  • Linux服务测试
  • Jenkins用户授权管理 企业级jenkins授权策略 jenkins用户权限分配
  • Flutter InheritedWidget 详解