泸州市网站建设_网站建设公司_模板建站_seo优化
2026/1/2 17:51:08 网站建设 项目流程

各位道友,贫道吕洞宾又来给大家讲Java设计模式啦!今天咱们要聊的是《On Java》里的模式重构案例,这可是个从"垃圾处理"到"高级工厂"再到"访问者巡游"的完整修仙之旅!

🗑️ 第一幕:垃圾的诞生与分类

话说在Java世界里,垃圾(Trash)可不是随便扔的,得讲究分类回收!咱们先看看最初的垃圾家族:

Trash和他的子类们

特征:

  • Trash是垃圾基类,定义了垃圾的基本属性

  • 每个子类代表不同类型的垃圾(纸、玻璃、铝等)

  • 每个垃圾都有重量和价值

代码示例:

// 垃圾基类 abstract class Trash { private double weight; Trash(double weight) { this.weight = weight; } abstract double getValue(); // 每种垃圾价值不同 double getWeight() { return weight; } // 计算总价值 double totalValue() { return weight * getValue(); } } // 具体垃圾类型 class Paper extends Trash { Paper(double weight) { super(weight); } double getValue() { return 0.10; } // 纸每公斤0.10元 } class Glass extends Trash { Glass(double weight) { super(weight); } double getValue() { return 0.20; } // 玻璃每公斤0.20元 } class Aluminum extends Trash { Aluminum(double weight) { super(weight); } double getValue() { return 1.50; } // 铝每公斤1.50元 }

反例分析:如果不用继承和多态:

// 糟糕的写法 - 用一堆if-else判断类型 class BadTrashHandler { void processTrash(Object trash) { if (trash instanceof Paper) { Paper p = (Paper)trash; double value = p.getWeight() * 0.10; // 处理纸... } else if (trash instanceof Glass) { Glass g = (Glass)trash; double value = g.getWeight() * 0.20; // 处理玻璃... } else if (trash instanceof Aluminum) { // 每新增一种垃圾类型,这里就要加一个if! } } }

问题:

  • 违反开闭原则,新增类型需要修改现有代码
  • 代码重复,相同的计算逻辑到处复制
  • 难以维护,if-else链会越来越长

优点:

  • 利用多态,新增类型不影响现有代码
  • 计算逻辑集中在基类,避免重复
  • 符合单一职责原则

📨 第二幕:信使对象登场

信使对象就像快递小哥,专门负责传递消息和数据!

特征:

  • 封装数据传递过程
  • 简化对象间的通信
  • 提高代码可读性

代码示例:

// 信使对象 - 传递垃圾信息 class TrashInfo { private String type; private double weight; private double value; TrashInfo(String type, double weight, double value) { this.type = type; this.weight = weight; this.value = value; } // 提供获取信息的方法,不暴露内部实现 String getDescription() { return String.format("%s: %.2fkg, ¥%.2f", type, weight, weight * value); } double getTotalValue() { return weight * value; } } // 使用信使对象 class RecyclingCenter { void processTrashInfo(TrashInfo info) { System.out.println("Processing: " + info.getDescription()); System.out.println("Total value: ¥" + info.getTotalValue()); } }

反例分析:如果不用信使对象:

// 糟糕的写法 - 直接传递多个参数 class BadRecyclingCenter { void processTrash(String type, double weight, double value) { // 参数太多,容易搞混顺序! System.out.println(type + ": " + weight + "kg"); // 如果以后要加新参数,所有调用处都要改! } } // 调用时: center.processTrash("Paper", 5.0, 0.10); center.processTrash("Glass", 3.0, 0.20); // 哪个是重量?哪个是价值?容易出错!

问题:

  • 参数过多,容易混淆
  • 修改参数需要修改所有调用处
  • 缺乏类型安全

优点:

  • 封装相关数据,提高内聚性
  • 参数变化不影响调用者
  • 提高代码可读性和可维护性

🏭 第三幕:工厂的进化之路

1. 普通工厂模式

特征:

  • 每个垃圾类型对应一个工厂方法
  • 简单直接,但不够灵活

代码示例:

class SimpleTrashFactory { Trash createPaper(double weight) { return new Paper(weight); } Trash createGlass(double weight) { return new Glass(weight); } Trash createAluminum(double weight) { return new Aluminum(weight); } }

2. 工厂通用化

特征:

  • 使用Map存储类型与创建函数的映射
  • 可以动态注册新类型
  • 更加灵活

代码示例:

import java.util.HashMap; import java.util.Map; import java.util.function.Function; class GenericTrashFactory { private Map<String, Function<Double, Trash>> creators = new HashMap<>(); GenericTrashFactory() { register("Paper", Paper::new); register("Glass", Glass::new); register("Aluminum", Aluminum::new); } void register(String type, Function<Double, Trash> creator) { creators.put(type, creator); } Trash create(String type, double weight) { Function<Double, Trash> creator = creators.get(type); if (creator == null) { throw new IllegalArgumentException("Unknown trash type: " + type); } return creator.apply(weight); } }

反例分析:如果不用通用工厂:

// 糟糕的写法 - 硬编码的工厂方法 class BadFactory { Trash create(String type, double weight) { switch(type) { case "Paper": return new Paper(weight); case "Glass": return new Glass(weight); case "Aluminum": return new Aluminum(weight); default: throw new IllegalArgumentException("Unknown type"); } // 每新增一种类型,就要修改switch语句! } }

问题:

  • 违反开闭原则
  • 工厂类会越来越臃肿
  • 难以扩展新类型

优点:

  • 符合开闭原则,新增类型只需注册
  • 工厂类保持简洁
  • 支持动态注册新类型

📄 第四幕:从文件解析垃圾

特征:

  • 从外部文件读取垃圾数据
  • 动态创建垃圾对象
  • 实现数据与代码的分离

代码示例:

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; class TrashParser { private GenericTrashFactory factory; TrashParser(GenericTrashFactory factory) { this.factory = factory; } List<Trash> parseFromFile(String filename) throws IOException { List<Trash> trashList = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { String line; while ((line = reader.readLine()) != null) { String[] parts = line.split(","); if (parts.length == 2) { String type = parts[0].trim(); double weight = Double.parseDouble(parts[1].trim()); trashList.add(factory.create(type, weight)); } } } return trashList; } } // 数据文件内容示例: // Paper, 5.0 // Glass, 3.0 // Aluminum, 2.0 // Paper, 1.5

反例分析:如果硬编码在代码中:

// 糟糕的写法 - 数据硬编码 class BadTrashLoader { List<Trash> loadTrash() { List<Trash> trashList = new ArrayList<>(); trashList.add(new Paper(5.0)); trashList.add(new Glass(3.0)); trashList.add(new Aluminum(2.0)); // 要改数据?得重新编译代码! return trashList; } }

问题:

  • 数据与代码耦合
  • 修改数据需要重新编译
  • 难以维护大量数据

优点:

  • 数据与代码分离
  • 可以动态修改数据
  • 支持多种数据源

🔄 第五幕:DynaFactory实现回收

DynaFactory就像个智能回收机器人,能动态识别和处理各种垃圾!

特征:

  • 使用反射动态创建对象
  • 无需预先知道所有类型
  • 高度灵活

代码示例:

import java.lang.reflect.Constructor; class DynaFactory { Trash create(String className, double weight) { try { Class<?> clazz = Class.forName(className); Constructor<?> constructor = clazz.getConstructor(double.class); return (Trash) constructor.newInstance(weight); } catch (Exception e) { throw new RuntimeException("Failed to create: " + className, e); } } } // 使用示例 DynaFactory factory = new DynaFactory(); Trash paper = factory.create("Paper", 5.0); Trash glass = factory.create("Glass", 3.0);

反例分析:如果不用反射:

// 糟糕的写法 - 需要知道所有类型 class StaticFactory { Trash create(String type, double weight) { // 必须预先知道所有可能类型 if ("Paper".equals(type)) { return new Paper(weight); } else if ("Glass".equals(type)) { return new Glass(weight); } else if ("Aluminum".equals(type)) { return new Aluminum(weight); } // 新增类型?得修改代码! return null; } }

问题:

  • 需要预先知道所有类型
  • 违反开闭原则
  • 难以支持插件式架构

优点:

  • 无需预先知道所有类型
  • 支持动态加载新类型
  • 高度灵活和可扩展

🎨 第六幕:用法抽象化

抽象化就像给代码穿上"隐身衣",让具体实现隐藏起来!

特征:

  • 定义抽象接口

  • 隐藏具体实现细节

  • 提高代码复用性

代码示例:

// 抽象接口 interface TrashProcessor { void process(Trash trash); double getTotalValue(); } // 具体实现1:简单处理器 class SimpleProcessor implements TrashProcessor { private double totalValue = 0; public void process(Trash trash) { totalValue += trash.totalValue(); System.out.println("Processed: " + trash.getClass().getSimpleName()); } public double getTotalValue() { return totalValue; } } // 具体实现2:详细处理器 class DetailedProcessor implements TrashProcessor { private double totalValue = 0; private int count = 0; public void process(Trash trash) { totalValue += trash.totalValue(); count++; System.out.printf("Processed #%d: %s (%.2fkg, ¥%.2f)%n", count, trash.getClass().getSimpleName(), trash.getWeight(), trash.totalValue()); } public double getTotalValue() { return totalValue; } } // 使用抽象接口 class RecyclingSystem { private TrashProcessor processor; RecyclingSystem(TrashProcessor processor) { this.processor = processor; } void processAll(List<Trash> trashList) { for (Trash trash : trashList) { processor.process(trash); } System.out.println("Total value: ¥" + processor.getTotalValue()); } }

反例分析:如果不抽象:

// 糟糕的写法 - 具体实现硬编码 class ConcreteSystem { void processAll(List<Trash> trashList) { double totalValue = 0; int count = 0; for (Trash trash : trashList) { totalValue += trash.totalValue(); count++; // 处理逻辑硬编码在这里 System.out.println("Processing trash #" + count); } System.out.println("Total: ¥" + totalValue); // 想换种处理方式?得重写整个方法! } }

问题:

  • 处理逻辑与系统耦合
  • 难以复用处理逻辑
  • 违反单一职责原则

优点:

  • 处理逻辑可替换

  • 符合开闭原则

  • 提高代码复用性

🤝 第七幕:多路分发重新设计

多路分发就像让两个对象"相亲",让他们自己决定怎么互动!

特征:

  • 根据多个对象的实际类型决定行为
  • 消除大量的if-else判断
  • 提高扩展性

代码示例:

// 使用多路分发处理垃圾回收 interface Trash { double accept(TrashVisitor visitor); } class Paper implements Trash { private double weight; Paper(double weight) { this.weight = weight; } public double getWeight() { return weight; } public double accept(TrashVisitor visitor) { return visitor.visitPaper(this); } } class Glass implements Trash { private double weight; Glass(double weight) { this.weight = weight; } public double getWeight() { return weight; } public double accept(TrashVisitor visitor) { return visitor.visitGlass(this); } } // 访问者接口 interface TrashVisitor { double visitPaper(Paper paper); double visitGlass(Glass glass); double visitAluminum(Aluminum aluminum); } // 具体访问者:价值计算器 class ValueCalculator implements TrashVisitor { public double visitPaper(Paper paper) { return paper.getWeight() * 0.10; } public double visitGlass(Glass glass) { return glass.getWeight() * 0.20; } public double visitAluminum(Aluminum aluminum) { return aluminum.getWeight() * 1.50; } } // 使用多路分发 class RecyclingPlant { double calculateTotalValue(List<Trash> trashList) { TrashVisitor calculator = new ValueCalculator(); double total = 0; for (Trash trash : trashList) { total += trash.accept(calculator); } return total; } }

反例分析:如果不用多路分发:

// 糟糕的写法 - 双重if-else判断 class BadCalculator { double calculateValue(Trash trash1, Trash trash2) { // 需要判断所有类型组合! if (trash1 instanceof Paper) { if (trash2 instanceof Paper) { return calculatePaperPaper((Paper)trash1, (Paper)trash2); } else if (trash2 instanceof Glass) { return calculatePaperGlass((Paper)trash1, (Glass)trash2); } // 更多判断... } else if (trash1 instanceof Glass) { // 更多判断... } // 每新增一种垃圾类型,这里就要指数级增加判断! return 0; } }

问题:

  • 判断逻辑指数级增长
  • 难以维护和扩展
  • 违反开闭原则

优点:

  • 新增类型只需添加新的visit方法
  • 判断逻辑分散到各个类中
  • 符合开闭原则

👤 第八幕:访问者模式巡游

访问者模式就像请专家来参观你的对象,让专家决定怎么处理它们!

特征:

  • 将算法与对象结构分离

  • 可以在不修改对象的情况下添加新操作

  • 双重分发机制

代码示例:

// 更完整的访问者模式实现 interface EnhancedTrashVisitor { double visit(Paper paper); double visit(Glass glass); double visit(Aluminum aluminum); String getReport(); } // 价值访问者 class ValueVisitor implements EnhancedTrashVisitor { private double totalValue = 0; private StringBuilder report = new StringBuilder(); public double visit(Paper paper) { double value = paper.getWeight() * 0.10; totalValue += value; report.append(String.format("Paper: %.2fkg -> ¥%.2f%n", paper.getWeight(), value)); return value; } public double visit(Glass glass) { double value = glass.getWeight() * 0.20; totalValue += value; report.append(String.format("Glass: %.2fkg -> ¥%.2f%n", glass.getWeight(), value)); return value; } public double visit(Aluminum aluminum) { double value = aluminum.getWeight() * 1.50; totalValue += value; report.append(String.format("Aluminum: %.2fkg -> ¥%.2f%n", aluminum.getWeight(), value)); return value; } public String getReport() { report.append(String.format("Total value: ¥%.2f", totalValue)); return report.toString(); } } // 重量访问者 class WeightVisitor implements EnhancedTrashVisitor { private double totalWeight = 0; public double visit(Paper paper) { totalWeight += paper.getWeight(); return paper.getWeight(); } public double visit(Glass glass) { totalWeight += glass.getWeight(); return glass.getWeight(); } public double visit(Aluminum aluminum) { totalWeight += aluminum.getWeight(); return aluminum.getWeight(); } public String getReport() { return String.format("Total weight: %.2fkg", totalWeight); } }

反例分析:如果不用访问者模式:

// 糟糕的写法 - 算法硬编码在对象中 class BadTrash { private double weight; private String type; // 每个算法都要加一个方法! double calculateValue() { if ("Paper".equals(type)) return weight * 0.10; if ("Glass".equals(type)) return weight * 0.20; if ("Aluminum".equals(type)) return weight * 1.50; return 0; } double calculateWeight() { return weight; // 这个还简单... } String generateReport() { // 报告生成逻辑也在这里! return type + ": " + weight + "kg"; } // 每新增一个算法,就要修改这个类! }

问题:

  • 违反单一职责原则
  • 对象类会越来越臃肿
  • 难以添加新算法

优点:

  • 算法与对象结构分离
  • 容易添加新操作
  • 对象类保持稳定

⚡ 第九幕:反射的利与弊

反射就像Java的"照妖镜",能看透类的内部结构,但用不好会伤到自己!

反射的优点:

  1. 动态性:运行时获取类信息
  2. 灵活性:无需在编译时知道具体类
  3. 通用性:可以编写通用框架和工具

代码示例:

import java.lang.reflect.Method; import java.util.Arrays; class ReflectionExample { void inspectClass(Object obj) { Class<?> clazz = obj.getClass(); System.out.println("Class name: " + clazz.getName()); System.out.println("Methods:"); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(" " + method.getName() + " -> " + Arrays.toString(method.getParameterTypes())); } } // 动态调用方法 Object invokeMethod(Object obj, String methodName, Object... args) throws Exception { Class<?> clazz = obj.getClass(); Method method = findMethod(clazz, methodName, args); method.setAccessible(true); // 可以访问私有方法! return method.invoke(obj, args); } private Method findMethod(Class<?> clazz, String methodName, Object... args) { for (Method method : clazz.getDeclaredMethods()) { if (method.getName().equals(methodName) && method.getParameterCount() == args.length) { return method; } } return null; } }

反射的缺点:

  1. 性能开销:反射调用比直接调用慢
  2. 安全性:可以绕过访问控制
  3. 类型安全:编译时无法检查类型
  4. 可读性:代码难以理解和维护

反例分析:滥用反射的后果:

// 糟糕的反射用法 class DangerousReflection { void hack(Object obj) throws Exception { Class<?> clazz = obj.getClass(); // 可以访问私有字段! Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); System.out.println(field.getName() + " = " + field.get(obj)); } // 可以调用私有方法! Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (method.getName().startsWith("secret")) { method.setAccessible(true); method.invoke(obj); // 调用秘密方法! } } } }

问题:

  • 破坏封装性
  • 绕过访问控制
  • 可能引发安全问题
  • 代码难以维护

使用建议:

  1. 框架和库:反射适合用于框架(如Spring、Hibernate)
  2. 序列化/反序列化:JSON/XML解析库
  3. 测试工具:单元测试框架
  4. 避免在业务逻辑中滥用:保持代码可读性和性能

📊 模式重构总结

重构步骤解决的问题使用模式关键改进
Trash子类垃圾分类处理继承/多态消除if-else,支持扩展
信使对象参数传递混乱值对象封装数据,提高可读性
工厂通用化硬编码创建逻辑工厂模式+Map动态注册,支持插件
文件解析数据与代码耦合解析器模式外部配置,动态加载
DynaFactory类型硬编码反射+工厂完全动态创建
用法抽象化逻辑与实现耦合策略模式算法可替换
多路分发类型判断爆炸访问者模式消除条件判断
访问者模式算法污染对象访问者模式分离算法与结构

💡 实战经验总结

  1. 何时用继承:对象有明确的"is-a"关系时
  2. 何时用组合:对象有"has-a"关系或需要动态变化时
  3. 何时用工厂:创建逻辑复杂或需要统一管理时
  4. 何时用访问者:需要在不修改对象的情况下添加新操作时
  5. 何时用反射:编写通用框架或需要极大灵活性时
  6. 何时不用反射:性能敏感或需要类型安全的业务逻辑

记住,设计模式就像武功招式:

  • 继承是"内功基础"——打好基础很重要
  • 多态是"招式变化"——灵活应对各种情况
  • 工厂是"兵器库"——统一管理创建过程
  • 访问者是"专家会诊"——请外援处理专业问题
  • 反射是"乾坤大挪移"——威力大但容易走火入魔

用对了事半功倍,用错了走火入魔!各位道友,修炼Java设计模式要循序渐进,切不可贪多求快。今天先讲到这里,咱们下次再见!🚀

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询