🎮 Java设计模式:从青铜到王者的代码修炼手册

作者 :一个热爱分享的程序猿 🐵
适合人群 :编程小白、设计模式新手、想写出优雅代码的你
难度指数:⭐⭐⭐ (别怕,咱们用人话讲!)


📖 目录

  1. 什么是设计模式?
  2. 设计模式的六大原则
  3. 创建型模式(5种)
  4. 结构型模式(7种)
  5. 行为型模式(11种)
  6. 实战技巧与建议

🤔 什么是设计模式?

想象一下,你是个大厨 👨‍🍳,每天要做各种菜。如果每次都瞎琢磨怎么做,那得累死!聪明的厨师会总结出一些"套路":

  • 炒菜套路:热锅→放油→爆香→翻炒→出锅
  • 炖汤套路:冷水下锅→大火烧开→小火慢炖→加盐出锅

设计模式就是编程界的"烹饪套路"! 🎯

它是前辈程序员在无数个996加班夜里,用头发和血泪总结出来的最佳实践。1994年,四位大神(GoF - Gang of Four)写了本书《设计模式》,总结了23种经典模式,从此成为程序员的"武林秘籍"。

为什么要学设计模式?

好处 比喻 说明
🏗️ 代码更易维护 房子有设计图 半年后回来看代码,不会问"这TM是谁写的?"
🔄 代码更易复用 乐高积木 写一次,到处用,不用重复造轮子
📈 代码更易扩展 手机装APP 需求变了?加个模块就行,不用推倒重来
💬 沟通更高效 黑话暗号 "用个单例",懂的都懂,不用解释半天

🎯 设计模式的六大原则

在学具体模式之前,先记住这六大金科玉律(就像学武功前要先练内功):

1️⃣ 单一职责原则 (SRP - Single Responsibility Principle)

人话版: 一个类只干一件事,别让它累死 😵

生活例子:

一个服务员不可能既做菜、又收银、还打扫卫生。分工明确,效率才高!

java 复制代码
// ❌ 不好的例子:一个类干太多事
class Employee {
    void calculateSalary() { }  // 算工资
    void saveToDatabase() { }   // 存数据库
    void generateReport() { }   // 生成报表
}

// ✅ 好的例子:职责分离
class SalaryCalculator {
    void calculate() { }
}
class EmployeeRepository {
    void save() { }
}
class ReportGenerator {
    void generate() { }
}

2️⃣ 开闭原则 (OCP - Open Closed Principle)

人话版: 对扩展开放,对修改关闭(新需求?加代码,别改老代码!)

生活例子:

你买了个手机,想要新功能就装个APP,不需要拆手机改硬件吧?📱

java 复制代码
// ❌ 不好的例子:每次加新图形都要改代码
class GraphicEditor {
    void drawShape(Shape s) {
        if (s.type == 1) drawRectangle(s);
        else if (s.type == 2) drawCircle(s);
        // 每次加新图形都要在这里加 if...太痛苦了!
    }
}

// ✅ 好的例子:使用多态,添加新图形不用改老代码
interface Shape {
    void draw();
}
class Rectangle implements Shape {
    void draw() { /* 画矩形 */ }
}
class Circle implements Shape {
    void draw() { /* 画圆形 */ }
}

3️⃣ 里氏替换原则 (LSP - Liskov Substitution Principle)

人话版: 子类可以替换父类,程序照样跑

生活例子:

老板说"找个人来送货",无论来的是正式员工还是临时工,送货这事儿都能干!🚚

java 复制代码
class Bird {
    void fly() { /* 飞翔 */ }
}

class Sparrow extends Bird {
    void fly() { /* 麻雀的飞法 */ }  // ✅ 可以
}

class Ostrich extends Bird {
    void fly() { 
        throw new Exception("鸵鸟不会飞!");  // ❌ 违反原则
    }
}

4️⃣ 依赖倒置原则 (DIP - Dependency Inversion Principle)

人话版: 依赖抽象,不要依赖具体实现

生活例子:

你用的是"充电接口"(抽象),不管是苹果充电器还是安卓充电器(具体实现),插上就能用!🔌

java 复制代码
// ❌ 不好的例子:直接依赖具体类
class Driver {
    private Benz car;  // 只能开奔驰,换辆车就不会开了?
    void drive() {
        car.run();
    }
}

// ✅ 好的例子:依赖抽象接口
interface Car {
    void run();
}
class Driver {
    private Car car;  // 任何实现Car接口的车都能开
    void drive() {
        car.run();
    }
}

5️⃣ 接口隔离原则 (ISP - Interface Segregation Principle)

人话版: 接口要小而精,不要大而全

生活例子:

你去银行办业务,只需要"取款"功能,不需要柜台把"贷款"、"理财"、"换汇"功能全塞给你吧?🏦

java 复制代码
// ❌ 不好的例子:接口太胖
interface Worker {
    void work();
    void eat();
    void sleep();
}
class Robot implements Worker {
    void work() { /* OK */ }
    void eat() { /* 机器人不吃饭!*/ }    // 尴尬
    void sleep() { /* 机器人不睡觉!*/ }  // 尴尬
}

// ✅ 好的例子:接口拆分
interface Workable {
    void work();
}
interface Eatable {
    void eat();
}
interface Sleepable {
    void sleep();
}

6️⃣ 迪米特法则 (LoD - Law of Demeter)

人话版: 最少知识原则,只跟朋友说话

生活例子:

你想买瓶可乐,直接给钱让朋友帮你买就行,不用管他怎么走到便利店、怎么挑选、怎么结账!💰

java 复制代码
// ❌ 不好的例子:知道太多细节
class Person {
    void buyCoke() {
        Wallet wallet = new Wallet();
        Money money = wallet.getMoney();
        Store store = new Store();
        Coke coke = store.getCoke();
        store.pay(money);
        // 细节暴露太多了!
    }
}

// ✅ 好的例子:只跟直接朋友通信
class Person {
    void buyCoke() {
        friend.buyFor(this);  // 让朋友帮忙买,不管细节
    }
}

🎨 创建型模式(5种)

创建型模式关注的是怎么优雅地创建对象。就像生孩子,有的一胎一个,有的一胎多个,还有的用克隆技术... 👶


1. 单例模式 (Singleton) 👑

💡 核心思想

全世界独此一份! 确保一个类只有一个实例,并提供全局访问点。

🌍 生活例子

  • 总统:一个国家同时只能有一个总统
  • Windows任务管理器:你打开多少次,都只有一个窗口
  • 公司的打印机服务:全公司共用一个打印服务

📊 UML图示

css 复制代码
┌─────────────────────┐
│     Singleton       │
├─────────────────────┤
│ - instance: Singleton │  (静态私有实例)
├─────────────────────┤
│ - Singleton()       │  (私有构造函数)
│ + getInstance(): Singleton │ (公共获取方法)
└─────────────────────┘

💻 代码实现

1️⃣ 饿汉式(推荐):

java 复制代码
/**
 * 饿汉式单例:类加载时就创建实例
 * 优点:线程安全,简单
 * 缺点:可能造成资源浪费(如果一直不用)
 */
public class President {
    // 类加载时就创建实例(饿汉:一上来就饿,先吃了再说)
    private static final President INSTANCE = new President();
    
    private String name;
    
    // 私有构造函数,防止外部 new
    private President() {
        this.name = "习大大";
        System.out.println("总统上任了!");
    }
    
    // 公共获取方法
    public static President getInstance() {
        return INSTANCE;
    }
    
    public void manage() {
        System.out.println(name + "正在治理国家...");
    }
}

// 使用示例
public class Test {
    public static void main(String[] args) {
        President p1 = President.getInstance();
        President p2 = President.getInstance();
        
        System.out.println(p1 == p2);  // true,是同一个对象!
        
        p1.manage();  // 习大大正在治理国家...
    }
}

2️⃣ 懒汉式(双重检查锁定):

java 复制代码
/**
 * 懒汉式单例:用的时候才创建
 * 优点:延迟加载,节省资源
 * 缺点:代码复杂
 */
public class TaskManager {
    // volatile 防止指令重排序
    private static volatile TaskManager instance;
    
    private TaskManager() {
        System.out.println("任务管理器启动!");
    }
    
    public static TaskManager getInstance() {
        if (instance == null) {  // 第一次检查
            synchronized (TaskManager.class) {  // 加锁
                if (instance == null) {  // 第二次检查
                    instance = new TaskManager();
                }
            }
        }
        return instance;
    }
    
    public void showProcesses() {
        System.out.println("显示正在运行的进程...");
    }
}

3️⃣ 枚举式(最优雅):

java 复制代码
/**
 * 枚举单例:最简洁、最安全的方式
 * 优点:防止反射攻击、防止序列化破坏、线程安全
 * 缺点:不能延迟加载
 */
public enum DatabaseConnection {
    INSTANCE;
    
    private Connection connection;
    
    DatabaseConnection() {
        // 初始化数据库连接
        System.out.println("数据库连接已建立!");
    }
    
    public void query(String sql) {
        System.out.println("执行SQL: " + sql);
    }
}

// 使用
DatabaseConnection.INSTANCE.query("SELECT * FROM users");

⚠️ 使用场景

  • ✅ 频繁创建和销毁的对象
  • ✅ 创建对象耗时或耗资源
  • ✅ 需要频繁访问数据库或文件
  • ❌ 需要多个实例的场景

🎭 现实应用

  • Spring框架中的Bean默认是单例
  • 数据库连接池
  • 线程池
  • 配置管理类

2. 工厂方法模式 (Factory Method) 🏭

💡 核心思想

不直接new对象,而是通过工厂来生产! 定义一个创建对象的接口,让子类决定实例化哪个类。

🍕 生活例子

你去披萨店点餐:

  • 你:"老板,来个披萨!"
  • 老板:"要什么口味?"
  • 你:"芝士的!"
  • 老板让芝士披萨工厂生产 → 给你一个芝士披萨

你不需要知道披萨怎么做,工厂帮你搞定一切!

📊 UML图示

scss 复制代码
       ┌──────────────┐
       │   Creator    │ (抽象工厂)
       ├──────────────┤
       │ + factoryMethod(): Product │
       │ + someOperation()          │
       └──────────────┘
              ▲
              │
      ┌───────┴────────┐
      │                │
┌─────┴──────┐  ┌──────┴──────┐
│ ConcreteCreatorA │  │ ConcreteCreatorB │
├────────────┤  ├─────────────┤
│ + factoryMethod() │  │ + factoryMethod() │
└────────────┘  └─────────────┘
      │                │
      └────────┬───────┘
               ▼
         ┌─────────┐
         │ Product │ (产品接口)
         └─────────┘

💻 代码实现

java 复制代码
// 产品接口:披萨
interface Pizza {
    void prepare();   // 准备
    void bake();      // 烘烤
    void cut();       // 切片
    void box();       // 装盒
}

// 具体产品:芝士披萨
class CheesePizza implements Pizza {
    public void prepare() { System.out.println("准备芝士披萨材料..."); }
    public void bake() { System.out.println("烘烤芝士披萨..."); }
    public void cut() { System.out.println("切芝士披萨..."); }
    public void box() { System.out.println("装盒芝士披萨..."); }
}

// 具体产品:蔬菜披萨
class VeggiePizza implements Pizza {
    public void prepare() { System.out.println("准备蔬菜披萨材料..."); }
    public void bake() { System.out.println("烘烤蔬菜披萨..."); }
    public void cut() { System.out.println("切蔬菜披萨..."); }
    public void box() { System.out.println("装盒蔬菜披萨..."); }
}

// 抽象工厂:披萨店
abstract class PizzaStore {
    // 工厂方法:由子类实现
    protected abstract Pizza createPizza(String type);
    
    // 业务方法
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);  // 调用工厂方法
        
        // 统一的制作流程
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }
}

// 具体工厂:纽约披萨店
class NYPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new CheesePizza();
        } else if (type.equals("veggie")) {
            return new VeggiePizza();
        }
        return null;
    }
}

// 使用示例
public class Test {
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        
        Pizza pizza = nyStore.orderPizza("cheese");
        // 输出:
        // 准备芝士披萨材料...
        // 烘烤芝士披萨...
        // 切芝士披萨...
        // 装盒芝士披萨...
    }
}

⚠️ 使用场景

  • ✅ 创建对象需要大量重复代码
  • ✅ 客户端不知道具体需要创建哪个类的实例
  • ✅ 一个类希望由其子类指定创建对象

3. 抽象工厂模式 (Abstract Factory) 🏭🏭

💡 核心思想

工厂的工厂! 提供一个创建一系列相关或相互依赖对象的接口,无需指定具体类。

🪑 生活例子

你要装修房子,需要买全套家具:

  • 现代风格套装:现代沙发 + 现代茶几 + 现代衣柜
  • 古典风格套装:古典沙发 + 古典茶几 + 古典衣柜

抽象工厂保证:你买的家具风格统一,不会出现"现代沙发配古典茶几"的悲剧!

💻 代码实现

java 复制代码
// 产品族接口:沙发
interface Sofa {
    void sit();
}

// 产品族接口:茶几
interface CoffeeTable {
    void place();
}

// 现代风格产品
class ModernSofa implements Sofa {
    public void sit() { System.out.println("坐在现代风格沙发上"); }
}
class ModernCoffeeTable implements CoffeeTable {
    public void place() { System.out.println("放在现代风格茶几上"); }
}

// 古典风格产品
class ClassicalSofa implements Sofa {
    public void sit() { System.out.println("坐在古典风格沙发上"); }
}
class ClassicalCoffeeTable implements CoffeeTable {
    public void place() { System.out.println("放在古典风格茶几上"); }
}

// 抽象工厂
interface FurnitureFactory {
    Sofa createSofa();
    CoffeeTable createCoffeeTable();
}

// 现代家具工厂
class ModernFurnitureFactory implements FurnitureFactory {
    public Sofa createSofa() { return new ModernSofa(); }
    public CoffeeTable createCoffeeTable() { return new ModernCoffeeTable(); }
}

// 古典家具工厂
class ClassicalFurnitureFactory implements FurnitureFactory {
    public Sofa createSofa() { return new ClassicalSofa(); }
    public CoffeeTable createCoffeeTable() { return new ClassicalCoffeeTable(); }
}

// 使用
public class Test {
    public static void main(String[] args) {
        // 客户选择现代风格
        FurnitureFactory factory = new ModernFurnitureFactory();
        
        Sofa sofa = factory.createSofa();
        CoffeeTable table = factory.createCoffeeTable();
        
        sofa.sit();        // 坐在现代风格沙发上
        table.place();     // 放在现代风格茶几上
        
        // 风格统一!✅
    }
}

4. 建造者模式 (Builder) 🏗️

💡 核心思想

分步骤构建复杂对象! 将对象的构建过程和表示分离,可以创建不同表示。

🍔 生活例子

你去麦当劳点汉堡:

  • "我要一个汉堡!"
  • "要不要芝士?" → 加芝士
  • "要不要培根?" → 加培根
  • "要不要生菜?" → 不要

一步步定制你的专属汉堡!

💻 代码实现

java 复制代码
// 产品:电脑
class Computer {
    private String cpu;          // 必需
    private String ram;          // 必需
    private String storage;      // 可选
    private String gpu;          // 可选
    private String monitor;      // 可选
    
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
        this.gpu = builder.gpu;
        this.monitor = builder.monitor;
    }
    
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", storage='" + storage + '\'' +
                ", gpu='" + gpu + '\'' +
                ", monitor='" + monitor + '\'' +
                '}';
    }
    
    // 建造者
    public static class Builder {
        // 必需参数
        private final String cpu;
        private final String ram;
        
        // 可选参数
        private String storage = "256GB SSD";
        private String gpu = "集成显卡";
        private String monitor = "无";
        
        public Builder(String cpu, String ram) {
            this.cpu = cpu;
            this.ram = ram;
        }
        
        public Builder storage(String storage) {
            this.storage = storage;
            return this;
        }
        
        public Builder gpu(String gpu) {
            this.gpu = gpu;
            return this;
        }
        
        public Builder monitor(String monitor) {
            this.monitor = monitor;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
}

// 使用示例
public class Test {
    public static void main(String[] args) {
        // 办公电脑:只要基本配置
        Computer officePC = new Computer.Builder("i5", "8GB")
                .build();
        
        // 游戏电脑:要高配
        Computer gamingPC = new Computer.Builder("i9", "32GB")
                .storage("2TB SSD")
                .gpu("RTX 4090")
                .monitor("4K显示器")
                .build();
        
        System.out.println(officePC);
        System.out.println(gamingPC);
    }
}

⚠️ 使用场景

  • ✅ 对象有很多参数,而且有些是可选的
  • ✅ 构造函数参数过多,可读性差
  • ✅ 需要创建不可变对象

🎭 现实应用

  • StringBuilder / StringBuffer
  • Lombok的@Builder注解
  • HTTP请求构建器

5. 原型模式 (Prototype) 🐑

💡 核心思想

克隆复制! 用原型实例指定创建对象的种类,通过复制这个原型创建新对象。

🐑 生活例子

还记得1996年的多莉羊吗?科学家通过克隆技术,复制出了一只一模一样的羊!

💻 代码实现

java 复制代码
// 实现Cloneable接口
class Sheep implements Cloneable {
    private String name;
    private int age;
    private String color;
    
    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
    
    // 重写clone方法
    @Override
    protected Sheep clone() {
        try {
            return (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    @Override
    public String toString() {
        return "Sheep{name='" + name + "', age=" + age + ", color='" + color + "'}";
    }
}

// 使用示例
public class Test {
    public static void main(String[] args) {
        // 原型羊
        Sheep dolly = new Sheep("多莉", 3, "白色");
        
        // 克隆10只羊
        for (int i = 1; i <= 10; i++) {
            Sheep cloneSheep = dolly.clone();
            System.out.println("第" + i + "只克隆羊: " + cloneSheep);
        }
    }
}

⚠️ 注意事项

  • 浅拷贝 vs 深拷贝问题
  • 如果对象包含引用类型,需要手动实现深拷贝

🏗️ 结构型模式(7种)

结构型模式关注的是怎么把类或对象组合成更大的结构。就像搭积木,怎么搭得既稳固又漂亮!🧱


6. 适配器模式 (Adapter) 🔌

💡 核心思想

转换接口! 将一个类的接口转换成客户期望的另一个接口,让原本不兼容的类可以合作。

🔌 生活例子

你去日本旅游,带的是中国的两孔插头,但日本是三孔插座。怎么办?买个转换插头(适配器)!

💻 代码实现

java 复制代码
// 目标接口:中国插头(两孔)
interface ChinesePlug {
    void chargeWith2Pins();
}

// 被适配者:日本插头(三孔)
class JapanesePlug {
    public void chargeWith3Pins() {
        System.out.println("使用三孔插头充电");
    }
}

// 适配器
class PlugAdapter implements ChinesePlug {
    private JapanesePlug japanesePlug;
    
    public PlugAdapter(JapanesePlug japanesePlug) {
        this.japanesePlug = japanesePlug;
    }
    
    @Override
    public void chargeWith2Pins() {
        System.out.println("使用适配器转换...");
        japanesePlug.chargeWith3Pins();
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        JapanesePlug japanesePlug = new JapanesePlug();
        ChinesePlug adapter = new PlugAdapter(japanesePlug);
        
        adapter.chargeWith2Pins();
        // 输出:
        // 使用适配器转换...
        // 使用三孔插头充电
    }
}

7. 装饰器模式 (Decorator) 🎁

💡 核心思想

动态添加功能! 不改变原有对象,给对象动态添加新功能。

☕ 生活例子

你点了一杯咖啡:

  • 基础:咖啡(10元)
  • 加糖 → 咖啡+糖(12元)
  • 加奶 → 咖啡+糖+奶(15元)
  • 加冰 → 咖啡+糖+奶+冰(18元)

每加一样,都是在原来基础上"装饰"!

💻 代码实现

java 复制代码
// 组件接口:饮料
interface Beverage {
    String getDescription();
    double cost();
}

// 具体组件:咖啡
class Coffee implements Beverage {
    @Override
    public String getDescription() {
        return "咖啡";
    }
    
    @Override
    public double cost() {
        return 10.0;
    }
}

// 装饰器抽象类
abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
    
    public CondimentDecorator(Beverage beverage) {
        this.beverage = beverage;
    }
}

// 具体装饰器:糖
class Sugar extends CondimentDecorator {
    public Sugar(Beverage beverage) {
        super(beverage);
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 糖";
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 2.0;
    }
}

// 具体装饰器:奶
class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) {
        super(beverage);
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + " + 奶";
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 3.0;
    }
}

// 使用示例
public class Test {
    public static void main(String[] args) {
        // 点一杯基础咖啡
        Beverage coffee = new Coffee();
        System.out.println(coffee.getDescription() + " = " + coffee.cost() + "元");
        
        // 加糖
        coffee = new Sugar(coffee);
        System.out.println(coffee.getDescription() + " = " + coffee.cost() + "元");
        
        // 再加奶
        coffee = new Milk(coffee);
        System.out.println(coffee.getDescription() + " = " + coffee.cost() + "元");
        
        // 输出:
        // 咖啡 = 10.0元
        // 咖啡 + 糖 = 12.0元
        // 咖啡 + 糖 + 奶 = 15.0元
    }
}

🎭 现实应用

  • Java I/O流:new BufferedReader(new FileReader("file.txt"))
  • Servlet过滤器链

8. 代理模式 (Proxy) 🕵️

💡 核心思想

找个代理人! 为其他对象提供一个代理,控制对这个对象的访问。

🏠 生活例子

你要买房,找个房产中介(代理),他帮你:

  • 过滤不合适的房源
  • 讨价还价
  • 办理手续

你不用直接跟房东打交道!

💻 代码实现

java 复制代码
// 接口:房屋
interface House {
    void rent();
}

// 真实对象:房东
class Landlord implements House {
    @Override
    public void rent() {
        System.out.println("租房成功!");
    }
}

// 代理:中介
class Agent implements House {
    private Landlord landlord;
    
    public Agent() {
        this.landlord = new Landlord();
    }
    
    @Override
    public void rent() {
        before();
        landlord.rent();  // 调用真实对象
        after();
    }
    
    private void before() {
        System.out.println("中介:筛选房源、带你看房...");
    }
    
    private void after() {
        System.out.println("中介:办理合同、收取中介费...");
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        House agent = new Agent();
        agent.rent();
        
        // 输出:
        // 中介:筛选房源、带你看房...
        // 租房成功!
        // 中介:办理合同、收取中介费...
    }
}

三种代理类型

类型 说明 使用场景
静态代理 编译时确定代理类 简单场景
动态代理 运行时生成代理类 Spring AOP
远程代理 代理不同地址空间的对象 RPC调用

9. 桥接模式 (Bridge) 🌉

💡 核心思想

分离抽象和实现! 把抽象和实现解耦,让它们可以独立变化。

🎨 生活例子

画图软件:

  • 形状:圆形、方形、三角形
  • 颜色:红色、绿色、蓝色

如果用继承:红圆形、绿圆形、蓝圆形、红方形、绿方形...(类爆炸💥)

用桥接模式:形状和颜色分开,自由组合!


10. 组合模式 (Composite) 🌳

💡 核心思想

树形结构! 将对象组合成树形结构,让客户端统一处理单个对象和组合对象。

📁 生活例子

电脑的文件系统:

复制代码
📁 我的电脑
  ├── 📁 文档
  │   ├── 📄 报告.docx
  │   └── 📄 总结.xlsx
  ├── 📁 图片
  │   ├── 🖼️ 照片1.jpg
  │   └── 🖼️ 照片2.png
  └── 📄 readme.txt

文件夹可以包含文件和文件夹,统一用"文件系统节点"来处理!

💻 代码实现

java 复制代码
// 抽象组件
abstract class FileSystemNode {
    protected String name;
    
    public FileSystemNode(String name) {
        this.name = name;
    }
    
    public abstract void display(int depth);
}

// 叶子节点:文件
class File extends FileSystemNode {
    public File(String name) {
        super(name);
    }
    
    @Override
    public void display(int depth) {
        System.out.println(" ".repeat(depth) + "📄 " + name);
    }
}

// 组合节点:文件夹
class Folder extends FileSystemNode {
    private List<FileSystemNode> children = new ArrayList<>();
    
    public Folder(String name) {
        super(name);
    }
    
    public void add(FileSystemNode node) {
        children.add(node);
    }
    
    public void remove(FileSystemNode node) {
        children.remove(node);
    }
    
    @Override
    public void display(int depth) {
        System.out.println(" ".repeat(depth) + "📁 " + name);
        for (FileSystemNode child : children) {
            child.display(depth + 2);
        }
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        Folder root = new Folder("我的电脑");
        
        Folder docs = new Folder("文档");
        docs.add(new File("报告.docx"));
        docs.add(new File("总结.xlsx"));
        
        Folder pics = new Folder("图片");
        pics.add(new File("照片1.jpg"));
        pics.add(new File("照片2.png"));
        
        root.add(docs);
        root.add(pics);
        root.add(new File("readme.txt"));
        
        root.display(0);
    }
}

11. 外观模式 (Facade) 🎭

💡 核心思想

简化复杂接口! 为子系统提供一个统一的高层接口,让子系统更易用。

🎬 生活例子

你要看电影:

  1. 打开投影仪
  2. 拉上窗帘
  3. 打开音响
  4. 调节音量
  5. 播放电影

太复杂了!有了"智能家居系统"(外观),只需说:"播放电影",全部自动完成!


12. 享元模式 (Flyweight) 🪶

💡 核心思想

共享对象,节省内存! 运用共享技术有效支持大量细粒度对象。

♟️ 生活例子

下围棋:

  • 棋盘有361个点
  • 如果每个棋子都new一个对象,太浪费内存了!
  • 实际上只需要2个对象:黑棋、白棋,通过坐标区分位置

🎭 现实应用

  • Java的String常量池
  • 数据库连接池
  • 线程池

🎭 行为型模式(11种)

行为型模式关注的是对象之间怎么协作、怎么通信。就像舞台上的演员,各司其职,配合默契!💃🕺


13. 策略模式 (Strategy) 🎯

💡 核心思想

定义一系列算法,让它们可以互相替换! 让算法的变化独立于使用算法的客户。

🚗 生活例子

你要去机场:

  • 打车:快,但贵 💸
  • 地铁:便宜,但挤 🚇
  • 公交:最便宜,但慢 🚌

根据不同情况,选择不同的出行策略!

💻 代码实现

java 复制代码
// 策略接口
interface TravelStrategy {
    void travel(String destination);
}

// 具体策略:打车
class TaxiStrategy implements TravelStrategy {
    @Override
    public void travel(String destination) {
        System.out.println("打车去" + destination + ",快速但昂贵!");
    }
}

// 具体策略:地铁
class SubwayStrategy implements TravelStrategy {
    @Override
    public void travel(String destination) {
        System.out.println("坐地铁去" + destination + ",便宜但拥挤!");
    }
}

// 具体策略:公交
class BusStrategy implements TravelStrategy {
    @Override
    public void travel(String destination) {
        System.out.println("坐公交去" + destination + ",最便宜但最慢!");
    }
}

// 上下文:旅行者
class Traveler {
    private TravelStrategy strategy;
    
    public void setStrategy(TravelStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void goTo(String destination) {
        strategy.travel(destination);
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        Traveler traveler = new Traveler();
        
        // 赶时间,打车!
        traveler.setStrategy(new TaxiStrategy());
        traveler.goTo("机场");
        
        // 不着急,坐公交
        traveler.setStrategy(new BusStrategy());
        traveler.goTo("公司");
    }
}

⚠️ 使用场景

  • ✅ 一个系统有许多类,它们仅仅是行为不同
  • ✅ 需要动态选择算法
  • ✅ 避免多重条件语句

14. 观察者模式 (Observer) 👀

💡 核心思想

发布-订阅机制! 一对多依赖,一个对象状态改变,所有依赖者都会收到通知。

📰 生活例子

你订阅了某个公众号:

  • 公众号发布新文章 → 你收到推送
  • 你取消关注 → 不再收到推送

这就是观察者模式!

💻 代码实现

java 复制代码
import java.util.*;

// 观察者接口
interface Observer {
    void update(String message);
}

// 具体观察者:粉丝
class Fan implements Observer {
    private String name;
    
    public Fan(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String message) {
        System.out.println(name + " 收到通知:" + message);
    }
}

// 主题接口
interface Subject {
    void attach(Observer observer);   // 订阅
    void detach(Observer observer);   // 取消订阅
    void notifyObservers();           // 通知
}

// 具体主题:公众号
class WeChatAccount implements Subject {
    private String name;
    private List<Observer> fans = new ArrayList<>();
    private String article;
    
    public WeChatAccount(String name) {
        this.name = name;
    }
    
    @Override
    public void attach(Observer observer) {
        fans.add(observer);
        System.out.println("新增粉丝!当前粉丝数:" + fans.size());
    }
    
    @Override
    public void detach(Observer observer) {
        fans.remove(observer);
        System.out.println("粉丝取关!当前粉丝数:" + fans.size());
    }
    
    @Override
    public void notifyObservers() {
        for (Observer fan : fans) {
            fan.update(article);
        }
    }
    
    public void publishArticle(String article) {
        this.article = article;
        System.out.println("\n" + name + " 发布新文章:" + article);
        notifyObservers();
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        WeChatAccount account = new WeChatAccount("Java技术栈");
        
        Fan fan1 = new Fan("小明");
        Fan fan2 = new Fan("小红");
        Fan fan3 = new Fan("小刚");
        
        account.attach(fan1);
        account.attach(fan2);
        account.attach(fan3);
        
        account.publishArticle("《设计模式入门》");
        
        System.out.println();
        account.detach(fan2);  // 小红取关了
        
        account.publishArticle("《Spring Boot实战》");
    }
}

🎭 现实应用

  • Java的事件监听机制
  • Spring的事件驱动
  • MQ消息队列
  • RxJava响应式编程

15. 模板方法模式 (Template Method) 📝

💡 核心思想

定义算法骨架,细节由子类实现! 在父类定义算法结构,将某些步骤延迟到子类。

🍳 生活例子

做菜的固定流程:

  1. 准备食材
  2. 热锅
  3. 炒菜(每个菜不同)
  4. 装盘

骨架固定,具体炒什么菜由子类决定!

💻 代码实现

java 复制代码
// 抽象类:做菜模板
abstract class CookingTemplate {
    // 模板方法(final防止子类修改流程)
    public final void cook() {
        prepareIngredients();
        heatPan();
        fry();  // 钩子方法,由子类实现
        serve();
    }
    
    // 具体方法
    private void prepareIngredients() {
        System.out.println("1. 准备食材");
    }
    
    private void heatPan() {
        System.out.println("2. 热锅");
    }
    
    // 抽象方法:由子类实现
    protected abstract void fry();
    
    private void serve() {
        System.out.println("4. 装盘上菜\n");
    }
}

// 具体类:炒青菜
class FryVegetables extends CookingTemplate {
    @Override
    protected void fry() {
        System.out.println("3. 大火快炒青菜");
    }
}

// 具体类:炖肉
class StewMeat extends CookingTemplate {
    @Override
    protected void fry() {
        System.out.println("3. 小火慢炖肉");
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        CookingTemplate veg = new FryVegetables();
        veg.cook();
        
        CookingTemplate meat = new StewMeat();
        meat.cook();
    }
}

🎭 现实应用

  • Java的InputStream(read方法)
  • Servlet的HttpServlet
  • Spring的JdbcTemplate

16. 命令模式 (Command) 🎮

💡 核心思想

把请求封装成对象! 将请求发送者和接收者解耦,支持撤销、重做、日志等功能。

🕹️ 生活例子

遥控器:

  • 按"开"键 → 电视打开
  • 按"关"键 → 电视关闭
  • 按"撤销"键 → 恢复上一步操作

你不需要知道电视怎么实现的,只需要按按钮!

💻 代码实现

java 复制代码
// 接收者:电视
class TV {
    public void turnOn() {
        System.out.println("电视打开了 📺");
    }
    
    public void turnOff() {
        System.out.println("电视关闭了 ⬛");
    }
}

// 命令接口
interface Command {
    void execute();   // 执行
    void undo();      // 撤销
}

// 具体命令:打开电视
class TurnOnCommand implements Command {
    private TV tv;
    
    public TurnOnCommand(TV tv) {
        this.tv = tv;
    }
    
    @Override
    public void execute() {
        tv.turnOn();
    }
    
    @Override
    public void undo() {
        tv.turnOff();
    }
}

// 具体命令:关闭电视
class TurnOffCommand implements Command {
    private TV tv;
    
    public TurnOffCommand(TV tv) {
        this.tv = tv;
    }
    
    @Override
    public void execute() {
        tv.turnOff();
    }
    
    @Override
    public void undo() {
        tv.turnOn();
    }
}

// 调用者:遥控器
class RemoteControl {
    private Command command;
    private Command lastCommand;  // 记录上一次命令,用于撤销
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
        lastCommand = command;
    }
    
    public void pressUndo() {
        if (lastCommand != null) {
            System.out.println("撤销上一步操作...");
            lastCommand.undo();
        }
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        TV tv = new TV();
        Command turnOn = new TurnOnCommand(tv);
        Command turnOff = new TurnOffCommand(tv);
        
        RemoteControl remote = new RemoteControl();
        
        remote.setCommand(turnOn);
        remote.pressButton();  // 打开电视
        
        remote.setCommand(turnOff);
        remote.pressButton();  // 关闭电视
        
        remote.pressUndo();    // 撤销,重新打开
    }
}

17. 责任链模式 (Chain of Responsibility) ⛓️

💡 核心思想

请求沿着链传递,直到有对象处理它! 避免请求发送者与接收者耦合。

📋 生活例子

请假流程:

  • 请1天假 → 组长批准
  • 请3天假 → 经理批准
  • 请7天假 → 总监批准
  • 请30天假 → 老板批准

请求沿着"组长→经理→总监→老板"链传递!

💻 代码实现

java 复制代码
// 抽象处理者
abstract class Approver {
    protected Approver nextApprover;  // 下一个处理者
    protected String name;
    
    public Approver(String name) {
        this.name = name;
    }
    
    public void setNext(Approver nextApprover) {
        this.nextApprover = nextApprover;
    }
    
    // 处理请假请求
    public abstract void handleRequest(int days);
}

// 具体处理者:组长
class TeamLeader extends Approver {
    public TeamLeader(String name) {
        super(name);
    }
    
    @Override
    public void handleRequest(int days) {
        if (days <= 1) {
            System.out.println(name + ":请" + days + "天假,批准!✅");
        } else {
            System.out.println(name + ":我批不了,转给上级...");
            if (nextApprover != null) {
                nextApprover.handleRequest(days);
            }
        }
    }
}

// 具体处理者:经理
class Manager extends Approver {
    public Manager(String name) {
        super(name);
    }
    
    @Override
    public void handleRequest(int days) {
        if (days <= 3) {
            System.out.println(name + ":请" + days + "天假,批准!✅");
        } else {
            System.out.println(name + ":我批不了,转给上级...");
            if (nextApprover != null) {
                nextApprover.handleRequest(days);
            }
        }
    }
}

// 具体处理者:总监
class Director extends Approver {
    public Director(String name) {
        super(name);
    }
    
    @Override
    public void handleRequest(int days) {
        if (days <= 7) {
            System.out.println(name + ":请" + days + "天假,批准!✅");
        } else {
            System.out.println(name + ":我批不了,转给老板...");
            if (nextApprover != null) {
                nextApprover.handleRequest(days);
            }
        }
    }
}

// 具体处理者:老板
class Boss extends Approver {
    public Boss(String name) {
        super(name);
    }
    
    @Override
    public void handleRequest(int days) {
        if (days <= 30) {
            System.out.println(name + ":请" + days + "天假,批准!✅");
        } else {
            System.out.println(name + ":请这么久?不批!❌");
        }
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        // 构建责任链
        Approver leader = new TeamLeader("张组长");
        Approver manager = new Manager("李经理");
        Approver director = new Director("王总监");
        Approver boss = new Boss("刘老板");
        
        leader.setNext(manager);
        manager.setNext(director);
        director.setNext(boss);
        
        // 请假
        System.out.println("====== 小明请1天假 ======");
        leader.handleRequest(1);
        
        System.out.println("\n====== 小红请3天假 ======");
        leader.handleRequest(3);
        
        System.out.println("\n====== 小刚请7天假 ======");
        leader.handleRequest(7);
        
        System.out.println("\n====== 小李请100天假 ======");
        leader.handleRequest(100);
    }
}

🎭 现实应用

  • Servlet的Filter过滤器链
  • Spring的拦截器
  • Netty的Pipeline

18-23. 其他行为型模式(快速了解)

18. 迭代器模式 (Iterator) 🔄

遍历集合元素! Java的Iterator就是这个模式。

java 复制代码
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

19. 中介者模式 (Mediator) 📞

对象间通过中介者通信! 就像房产中介,买家卖家不直接联系。

生活例子: 机场调度塔台,所有飞机通过塔台协调,不互相通信。


20. 备忘录模式 (Memento) 💾

保存和恢复对象状态! 就像游戏存档。

生活例子: 你在玩《塞尔达传说》,打BOSS前先存个档,死了可以读档重来!


21. 状态模式 (State) 🚦

对象根据状态改变行为!

生活例子: 红绿灯

  • 红灯 → 停止
  • 黄灯 → 等待
  • 绿灯 → 通行

22. 访问者模式 (Visitor) 🚶

在不修改类的前提下,定义新操作!

生活例子: 商场的顾客(访问者),可以买衣服、买食品、买电器,但商品类不需要修改。


23. 解释器模式 (Interpreter) 🔤

定义语言的文法,并解释执行!

生活例子: 计算器解析"1 + 2 * 3"这样的表达式。


🎯 实战技巧与建议

📚 学习路线图

复制代码
第1阶段:入门(1-2周)
├── 理解六大原则
├── 掌握常用模式:单例、工厂、观察者
└── 模仿代码,多练习

第2阶段:进阶(1-2个月)
├── 学习全部23种模式
├── 看Spring源码中的应用
└── 在项目中尝试使用

第3阶段:精通(持续学习)
├── 灵活组合多种模式
├── 根据场景选择最优方案
└── 总结自己的设计经验

🤔 如何选择设计模式?

场景 推荐模式
需要全局唯一对象 单例模式
需要创建复杂对象 建造者模式
需要创建大量相似对象 工厂模式
需要动态添加功能 装饰器模式
接口不兼容 适配器模式
需要发布-订阅机制 观察者模式
需要多种算法可切换 策略模式
需要控制访问 代理模式
需要撤销/重做 命令模式

⚠️ 常见误区

❌ 误区1:滥用设计模式

反例: 一个简单的登录功能,非要用上单例、工厂、策略、观察者...过度设计!

正解: 简单问题简单做,不要为了用模式而用模式。


❌ 误区2:死记硬背

反例: 只背定义和代码,不理解原理和场景。

正解: 理解模式的设计思想解决的问题,才能灵活运用。


❌ 误区3:一成不变

反例: 书上怎么写就怎么用,不敢改。

正解: 设计模式是参考 ,不是教条。根据实际情况调整!


💪 实战建议

  1. 多看优秀源码

    • Spring框架
    • JDK源码
    • Apache Commons
  2. 多做练习

    • 用设计模式重构老代码
    • 在新项目中应用
    • 参与开源项目
  3. 多思考总结

    • 为什么这样设计?
    • 还有更好的方案吗?
    • 写技术博客记录

🎉 结语

恭喜你!🎊 读完这篇超长的设计模式指南,你已经从青铜段位晋级到白银了!

记住这几点:

  1. 设计模式不是银弹 🔫

    不要为了用模式而用模式,简单问题简单做。

  2. 理解比记忆更重要 🧠

    搞懂模式解决什么问题,比背代码重要。

  3. 实践出真知 💻

    光看不练假把式,多写代码才能掌握。

  4. 持续学习 📚

    设计模式是起点不是终点,继续探索架构设计、领域驱动设计(DDD)等更高级的内容。


📖 推荐阅读

  1. 📘 《设计模式:可复用面向对象软件的基础》(GoF圣经)
  2. 📗 《Head First 设计模式》(图解,通俗易懂)
  3. 📙 《大话设计模式》(中文,风趣幽默)
  4. 📕 《重构:改善既有代码的设计》(实战必读)

🙏 致谢

感谢你的耐心阅读!如果这篇文档对你有帮助,请:

  • ⭐ 点个赞
  • 🔄 转发分享
  • 💬 留言交流

最后送你一句话:

优秀的程序员写代码,卓越的程序员写模式! 🚀


🎮 愿你早日成为设计模式王者!

Happy Coding! 💻✨

相关推荐
兮动人3 小时前
Java 线程详解
后端
纪卓志George3 小时前
从 AWS 故障反思:广告系统的全球单元化部署
后端·架构
用户904706683574 小时前
redis-cli Could not connect to Redis at 127.0.0.1:6379: Connection refused
后端
学习OK呀4 小时前
python 多环境下配置运行
后端
马尚道4 小时前
Java高手速成--吃透源码+手写组件+定制开发教程
java
我命由我123454 小时前
Spring Cloud - Spring Cloud 注册中心与服务提供者(Spring Cloud Eureka 概述、微服务快速入门、微服务应用实例)
java·spring boot·spring·spring cloud·微服务·eureka·java-ee
MetaverseMan4 小时前
Java Spring 框架的`@Autowired` 注解 以及依赖注入分析
java·开发语言·spring
一吃就胖的4 小时前
【给服务器安装服务器安装nacos】
java·运维·服务器
码住懒羊羊4 小时前
【C++】stack|queue|deque
java·开发语言·c++