枣庄市网站建设_网站建设公司_MySQL_seo优化
2026/1/2 17:51:08 网站建设 项目流程

各位道友,贫道吕洞宾又来给大家讲Java设计模式啦!今天咱们不炼丹,改讲"接口变形术"、“代码翻译官”、“消息小灵通"和"多重分身术”!准备好你的Java飞剑,咱们开始吧!

🔄 改变接口:给代码"整容"的艺术

有时候啊,咱们的代码就像相亲一样——你看上的对象接口不对,怎么办?总不能重新投胎吧?这时候就需要"改变接口"的设计模式来帮忙了!

1. 适配器模式:代码界的"转接头"

适配器模式就像给你的旧手机配个Type-C转接头,让新充电器也能用!

特征:

  • 将一个类的接口转换成客户端期望的另一个接口
  • 让原本不兼容的类可以一起工作
  • 就像翻译官,让说不同语言的对象能沟通

代码示例:

// 旧接口 - 就像老式圆孔耳机插口 interface OldPlayer { void playMp3(String fileName); } // 新接口 - 新式Type-C接口 interface NewPlayer { void playAudio(String file); } // 旧实现类 class OldMp3Player implements OldPlayer { public void playMp3(String fileName) { System.out.println("播放MP3: " + fileName); } } // 适配器 - 转接头来了! class PlayerAdapter implements NewPlayer { private OldPlayer oldPlayer; PlayerAdapter(OldPlayer oldPlayer) { this.oldPlayer = oldPlayer; } public void playAudio(String file) { // 把新接口调用转成旧接口调用 oldPlayer.playMp3(file); } } // 使用 NewPlayer player = new PlayerAdapter(new OldMp3Player()); player.playAudio("song.mp3"); // 成功播放!

反例分析:如果不用适配器,代码会变成这样:

// 糟糕的写法 - 直接修改客户端代码 class Client { void playMusic(OldPlayer player) { // 需要知道旧接口的细节 if (player instanceof OldMp3Player) { ((OldMp3Player)player).playMp3("song.mp3"); } // 每新增一种播放器就要修改这里! } }

问题:

  • 客户端需要知道具体实现类的细节
  • 违反开闭原则,每次新增类型都要修改客户端
  • 代码耦合度高,难以维护

优点:

  • 让不兼容的接口能够协同工作

  • 提高代码复用性

  • 符合开闭原则

缺点:

  • 增加系统复杂度
  • 过多使用会让系统变得混乱

2. 外观模式:代码界的"前台小姐姐"

外观模式就像公司前台,你不需要知道公司内部有多少部门,找前台小姐姐就行!

特征:

  • 为复杂的子系统提供一个统一的接口
  • 隐藏系统的复杂性
  • 客户端只需要和外观类交互

代码示例:

// 复杂的子系统 - 就像公司各个部门 class CPU { void start() { System.out.println("CPU启动"); } void execute() { System.out.println("CPU执行指令"); } } class Memory { void load() { System.out.println("内存加载"); } } class HardDisk { void read() { System.out.println("硬盘读取"); } } // 外观类 - 公司前台 class ComputerFacade { private CPU cpu; private Memory memory; private HardDisk hardDisk; ComputerFacade() { this.cpu = new CPU(); this.memory = new Memory(); this.hardDisk = new HardDisk(); } // 统一接口 - 开机按钮 void startComputer() { System.out.println("=== 电脑开机 ==="); hardDisk.read(); memory.load(); cpu.start(); cpu.execute(); System.out.println("=== 开机完成 ==="); } } // 使用 ComputerFacade computer = new ComputerFacade(); computer.startComputer(); // 一键开机,多简单!

反例分析:如果不用外观模式:

// 糟糕的写法 - 客户端需要了解所有细节 class Client { void startComputer() { CPU cpu = new CPU(); Memory memory = new Memory(); HardDisk hardDisk = new HardDisk(); // 需要知道正确的启动顺序 hardDisk.read(); memory.load(); cpu.start(); cpu.execute(); // 如果顺序错了,电脑就开不了机! } }

问题:

  • 客户端需要了解子系统所有细节
  • 客户端与子系统高度耦合
  • 修改子系统会影响所有客户端

优点:

  • 简化客户端使用
  • 降低系统耦合度
  • 提高子系统独立性

缺点:

  • 不符合开闭原则(新增功能可能需要修改外观)
  • 可能变成"上帝类"(什么都管)

🧠 解释器模式:代码界的"翻译官"

解释器模式就像给你配了个随身翻译,你说"我要喝咖啡",翻译官帮你转换成机器能懂的指令!

特征:

  • 定义语言的文法规则
  • 构建解释器来解释语言中的句子
  • 适用于需要解释执行的语言

代码示例:

// 抽象表达式 interface Expression { int interpret(Context context); } // 终结符表达式 - 数字 class NumberExpression implements Expression { private int number; NumberExpression(int number) { this.number = number; } public int interpret(Context context) { return number; } } // 非终结符表达式 - 加法 class AddExpression implements Expression { private Expression left; private Expression right; AddExpression(Expression left, Expression right) { this.left = left; this.right = right; } public int interpret(Context context) { return left.interpret(context) + right.interpret(context); } } // 上下文 class Context { // 可以存储变量等信息 } // 使用 Expression expression = new AddExpression( new NumberExpression(10), new AddExpression( new NumberExpression(5), new NumberExpression(3) ) ); int result = expression.interpret(new Context()); System.out.println("10 + (5 + 3) = " + result); // 输出: 18

反例分析:如果不用解释器模式:

// 糟糕的写法 - 硬编码解析逻辑 class Calculator { int calculate(String expression) { // 需要自己解析字符串 if (expression.contains("+")) { String[] parts = expression.split("\\+"); // 还要处理嵌套括号、优先级等 // 代码会非常复杂! } return 0; } }

问题:

  • 解析逻辑与业务逻辑混在一起
  • 难以扩展新的语法规则
  • 代码复杂,难以维护

优点:

  • 容易扩展新的语法规则
  • 实现简单语法很容易
  • 符合单一职责原则

缺点:

  • 复杂文法难以维护
  • 执行效率较低
  • 类数量会很多

📞 回调模式:代码界的"消息小灵通"

回调模式就像你给朋友留个电话:"有事打我电话!"朋友有事就call你。

观察者模式:订阅-发布系统

观察者模式就像微信公众号,你关注了,公众号一更新你就收到推送!

特征:

  • 定义对象间的一对多依赖关系
  • 当一个对象状态改变时,所有依赖它的对象都得到通知
  • 也叫发布-订阅模式

代码示例:

// 观察者接口 interface Observer { void update(String message); } // 主题接口 interface Subject { void attach(Observer observer); void detach(Observer observer); void notifyObservers(); } // 具体主题 - 微信公众号 class WeChatPublicAccount implements Subject { private List<Observer> observers = new ArrayList<>(); private String latestArticle; public void attach(Observer observer) { observers.add(observer); } public void detach(Observer observer) { observers.remove(observer); } public void notifyObservers() { for (Observer observer : observers) { observer.update(latestArticle); } } // 发布新文章 void publishArticle(String article) { this.latestArticle = article; System.out.println("公众号发布了新文章: " + article); notifyObservers(); } } // 具体观察者 - 用户 class User implements Observer { private String name; User(String name) { this.name = name; } public void update(String message) { System.out.println(name + " 收到推送: " + message); } } // 使用 WeChatPublicAccount account = new WeChatPublicAccount(); User user1 = new User("张三"); User user2 = new User("李四"); account.attach(user1); account.attach(user2); account.publishArticle("Java设计模式详解"); // 输出: // 公众号发布了新文章: Java设计模式详解 // 张三 收到推送: Java设计模式详解 // 李四 收到推送: Java设计模式详解

反例分析:如果不用观察者模式:

// 糟糕的写法 - 主题直接调用所有观察者 class BadPublicAccount { private List<User> users = new ArrayList<>(); void addUser(User user) { users.add(user); } void publishArticle(String article) { System.out.println("发布文章: " + article); // 需要知道User的具体实现 for (User user : users) { user.receiveArticle(article); // 方法名硬编码! } } } class User { void receiveArticle(String article) { // 只能接收文章,不能接收其他类型消息 } }

问题:

  • 主题与观察者紧耦合
  • 难以扩展新的观察者类型
  • 违反开闭原则

优点:

  • 降低耦合度
  • 支持广播通信
  • 符合开闭原则

缺点:

  • 观察者过多时通知开销大
  • 可能引起循环引用

🎭 多路分发:代码界的"多重分身术"

多路分发就像你同时跟好几个人聊天,根据对方是谁和聊什么内容,给出不同的回复。

特征:

  • 根据多个对象的实际类型决定调用哪个方法

  • Java本身只支持单分发(根据接收者类型)

  • 通过设计模式实现多分发

代码示例:

// 游戏角色接口 interface Character { String fight(Character opponent); String fightAgainst(Knight knight); String fightAgainst(Wizard wizard); String fightAgainst(Dragon dragon); } // 具体角色 class Knight implements Character { public String fight(Character opponent) { return opponent.fightAgainst(this); } public String fightAgainst(Knight knight) { return "骑士 vs 骑士: 决斗开始!"; } public String fightAgainst(Wizard wizard) { return "骑士 vs 法师: 冲锋!"; } public String fightAgainst(Dragon dragon) { return "骑士 vs 龙: 屠龙勇士!"; } } class Wizard implements Character { public String fight(Character opponent) { return opponent.fightAgainst(this); } public String fightAgainst(Knight knight) { return "法师 vs 骑士: 火球术!"; } public String fightAgainst(Wizard wizard) { return "法师 vs 法师: 魔法对决!"; } public String fightAgainst(Dragon dragon) { return "法师 vs 龙: 召唤元素!"; } } class Dragon implements Character { public String fight(Character opponent) { return opponent.fightAgainst(this); } public String fightAgainst(Knight knight) { return "龙 vs 骑士: 喷火!"; } public String fightAgainst(Wizard wizard) { return "龙 vs 法师: 魔法抗性!"; } public String fightAgainst(Dragon dragon) { return "龙 vs 龙: 同类不相残"; } } // 使用 Character knight = new Knight(); Character wizard = new Wizard(); Character dragon = new Dragon(); System.out.println(knight.fight(wizard)); // 骑士 vs 法师 System.out.println(wizard.fight(dragon)); // 法师 vs 龙 System.out.println(dragon.fight(knight)); // 龙 vs 骑士

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

// 糟糕的写法 - 使用大量if-else class BadCharacter { String fight(BadCharacter opponent) { if (this instanceof Knight) { if (opponent instanceof Knight) { return "骑士 vs 骑士"; } else if (opponent instanceof Wizard) { return "骑士 vs 法师"; } // 每新增一个角色类型,这里就要加一个if! } else if (this instanceof Wizard) { // 同样需要很多if判断 } return "未知战斗"; } }

问题:

  • 代码臃肿,大量if-else语句
  • 违反开闭原则
  • 难以维护和扩展

优点:

  • 消除条件判断
  • 易于扩展新类型
  • 代码更优雅

缺点:

  • 类数量增多
  • 理解成本较高

📊 模式对比总结

模式适用场景核心思想优点缺点
适配器模式接口不兼容需要协作转换接口复用旧代码,解耦增加复杂度
外观模式简化复杂子系统统一接口简化使用,降低耦合可能违反开闭原则
解释器模式需要解释特定语言解释执行易于扩展语法效率低,复杂文法难维护
观察者模式一对多依赖关系发布-订阅解耦,支持广播可能引起循环引用
多路分发多类型交互双重虚拟调用消除条件判断类数量多

💡 实战应用建议

  1. 何时用适配器
    • 想使用现有类但接口不匹配时
    • 系统需要复用一些类,但这些类接口不符合系统需求
    • 想创建一个可以复用的类,与不相关类协同工作
  2. 何时用外观
    • 为复杂子系统提供简单接口
    • 客户端与多个子系统耦合严重时
    • 需要分层构建系统时
  3. 何时用解释器
    • 需要解释简单语言时
    • 文法规则相对固定时
    • 效率要求不高时
  4. 何时用观察者
    • 一个对象状态改变需要通知其他对象
    • 需要建立触发链时
    • 广播通知场景
  5. 何时用多路分发
    • 多个对象类型需要交互
    • 想避免大量if-else判断
    • 类型组合爆炸时

🎯 组合使用案例

// 组合使用多个模式 // 外观 + 观察者 + 适配器 // 旧系统接口 interface OldNotificationSystem { void sendSMS(String message); } // 新系统接口 interface NewNotificationSystem { void notify(String message); } // 适配器 class NotificationAdapter implements NewNotificationSystem { private OldNotificationSystem oldSystem; NotificationAdapter(OldNotificationSystem oldSystem) { this.oldSystem = oldSystem; } public void notify(String message) { oldSystem.sendSMS(message); } } // 观察者 interface Subscriber { void receive(String message); } // 外观 - 统一的通知中心 class NotificationCenter { private List<Subscriber> subscribers = new ArrayList<>(); private NewNotificationSystem notificationSystem; NotificationCenter(NewNotificationSystem system) { this.notificationSystem = system; } void subscribe(Subscriber subscriber) { subscribers.add(subscriber); } void broadcast(String message) { // 使用适配后的系统 notificationSystem.notify(message); // 通知所有观察者 for (Subscriber subscriber : subscribers) { subscriber.receive(message); } } }

记住,设计模式就像武功招式,用对了威力无穷,用错了就是花拳绣腿。关键是要理解每个模式的适用场景,不要为了用模式而用模式!

好了,今天的Java设计模式课就到这里。贫道要去修炼(写代码)了,下次再见!记得多练习,代码就像内功,越练越深厚!🚀

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

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

立即咨询