一些开发中常见的设计模式

一、设计模式快速指南(附例子)

1. 单例模式(Singleton)
  • 目标:确保一个类只有一个实例,并提供全局访问点。

  • 例子

    • 比如电脑的任务管理器,无论你打开多少次,它只会显示同一个窗口。

    • 代码中的数据库连接池,全局共享一个实例。

  • 关键代码:私有构造函数 + 静态获取实例方法。

public class Singleton {
    private static Singleton instance;
    private Singleton() {}  // 私有化构造函数
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2. 工厂模式(Factory)
  • 目标:将对象的创建逻辑封装起来,让调用者不直接依赖具体类。

  • 例子

    • 你去餐厅点餐,告诉服务员“我要一份汉堡”,厨房(工厂)决定做牛肉汉堡还是鸡肉汉堡,你不需要关心具体怎么做。

    • 代码中创建不同数据库连接(MySQL、Oracle)。

// 抽象产品
interface Food {
    void cook();
}
// 具体产品
class Burger implements Food {
    public void cook() { System.out.println("做汉堡"); }
}
// 工厂
class FoodFactory {
    public Food createFood(String type) {
        if ("burger".equals(type)) return new Burger();
        // 其他类型...
        return null;
    }
}

3. 观察者模式(Observer)
  • 目标:当一个对象状态改变时,自动通知所有依赖它的对象。

  • 例子

    • 微信公众号:你订阅了某个公众号,当它发新文章时,所有订阅者都会收到通知。

    • 代码中的事件监听机制(如按钮点击事件)。

// 观察者接口
interface Observer {
    void update(String message);
}
// 被观察者(主题)
class WeChatPublic {
    private List observers = new ArrayList<>();
    public void addObserver(Observer o) { observers.add(o); }
    public void notify(String msg) {
        for (Observer o : observers) {
            o.update(msg);
        }
    }
}

4. 装饰器模式(Decorator)
  • 目标:动态地给对象添加额外功能,避免继承导致的类爆炸。

  • 例子

    • 买奶茶:先点一杯原味奶茶,可以加珍珠、加椰果、加奶盖,每次加料都是“装饰”。

    • Java中的BufferedReader是对FileReader的装饰,添加了缓冲功能。

// 基础组件
interface MilkTea {
    String getDescription();
    double getCost();
}
// 装饰器基类
abstract class ToppingDecorator implements MilkTea {
    protected MilkTea milkTea;
    public ToppingDecorator(MilkTea milkTea) {
        this.milkTea = milkTea;
    }
}
// 具体装饰:加珍珠
class Pearl extends ToppingDecorator {
    public Pearl(MilkTea milkTea) { super(milkTea); }
    public String getDescription() {
        return milkTea.getDescription() + "+珍珠";
    }
    public double getCost() { return milkTea.getCost() + 3.0; }
}

5. 适配器模式(Adapter)
  • 目标:让不兼容的接口能够协同工作。

  • 例子

    • 电源转换器:将欧洲标准的插头(不兼容)转换成中国标准的插座。

    • 代码中旧系统接口适配新系统需求。

// 旧接口:欧洲插头
interface EuropePlug {
    void chargeWithTwoPins();
}
// 新需求:中国插座
interface ChinaSocket {
    void chargeWithThreeHoles();
}
// 适配器
class PlugAdapter implements ChinaSocket {
    private EuropePlug plug;
    public PlugAdapter(EuropePlug plug) { this.plug = plug; }
    public void chargeWithThreeHoles() {
        plug.chargeWithTwoPins();  // 调用旧方法,但实现了新接口
        System.out.println("通过适配器转换为三孔充电");
    }
}

6. 责任链模式(Chain of Responsibility)
  • 目标:让多个对象都有机会处理请求,避免请求发送者与接收者耦合。

  • 例子

    • 公司报销流程:员工提交报销单,金额≤1000由组长审批,≤5000由经理审批,更高金额由CEO审批。

    • Java Web中的过滤器链(Filter Chain)。

abstract class Approver {
    protected Approver nextApprover;
    public void setNext(Approver next) { this.nextApprover = next; }
    public abstract void handleRequest(double amount);
}

class Manager extends Approver {
    public void handleRequest(double amount) {
        if (amount <= 5000) {
            System.out.println("经理审批通过");
        } else if (nextApprover != null) {
            nextApprover.handleRequest(amount);
        }
    }
}

7. 代理模式(Proxy)
  • 目标:通过代理对象控制对原始对象的访问(如权限校验、延迟加载等)。

  • 例子

    • 明星经纪人:你想联系明星,必须先通过经纪人。

    • 代码中的数据库连接池(代理管理真实连接)。

interface Image {
    void display();
}
// 真实对象:大图片(加载慢)
class RealImage implements Image {
    public RealImage(String filename) { loadFromDisk(); }
    private void loadFromDisk() { System.out.println("加载图片..."); }
    public void display() { System.out.println("显示图片"); }
}
// 代理:延迟加载
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;
    public ProxyImage(String filename) { this.filename = filename; }
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

8. 建造者模式(Builder)
  • 目标:将复杂对象的构建过程拆解,使得同样的构建过程可以创建不同的表示。

  • 例子

    • 组装电脑:你可以选择不同的CPU、内存、硬盘,但组装流程固定(装主板→装CPU→装内存→装硬盘)。

    • Java中的StringBuilder

class Computer {
    private String cpu;
    private String ram;
    // 私有构造函数,只能通过Builder创建
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
    }
    // 建造者
    public static class Builder {
        private String cpu;
        private String ram;
        public Builder setCpu(String cpu) { this.cpu = cpu; return this; }
        public Builder setRam(String ram) { this.ram = ram; return this; }
        public Computer build() { return new Computer(this); }
    }
}

// 使用
Computer computer = new Computer.Builder()
    .setCpu("Intel i7")
    .setRam("32GB")
    .build();

二、编程核心思想

1. SOLID 原则
  • S(单一职责原则):一个类只做一件事。

    • 例子:用户管理类不应该同时处理登录和发送邮件。

  • O(开闭原则):对扩展开放,对修改关闭。

    • 例子:新增支付方式时,不应修改原有支付代码,而是添加新策略类。

  • L(里氏替换原则):子类必须能替换父类,且行为一致。

    • 例子ArrayList 可以替换 List,但不会改变集合的基本行为。

  • I(接口隔离原则):接口要小而专,不要大而全。

    • 例子:不要设计一个包含“打印”“扫描”“传真”的万能接口,拆分成多个接口。

  • D(依赖倒置原则):依赖抽象,而非具体实现。

    • 例子:订单服务依赖“支付接口”,而不是具体的“支付宝支付类”。


2. DRY(Don't Repeat Yourself)
  • 目标:避免重复代码,通过抽象复用逻辑。

  • 反面例子:多个类中有相同的校验逻辑,应提取到公共工具类中。


3. KISS(Keep It Simple, Stupid)
  • 目标:代码简单易懂,避免过度设计。

  • 反面例子:为了一个简单的配置读取功能引入复杂的依赖注入框架。


4. 高内聚低耦合
  • 高内聚:模块内部高度相关(如一个类的方法都围绕核心功能)。

  • 低耦合:模块之间依赖尽可能少(如通过接口调用而非直接依赖具体类)。


5. 面向接口编程
  • 核心:定义行为契约(接口),而非依赖具体实现。

  • 例子:数据库操作基于DataSource接口,而不是直接写死MySQLConnection


三、如何选择设计模式?

  1. 先理解问题:不要为了用模式而用模式,先明确你要解决什么问题。

  2. 匹配场景

    • 需要灵活扩展?→ 策略模式、装饰器模式

    • 需要统一流程?→ 模板模式、责任链模式

    • 需要隐藏复杂性?→ 外观模式、代理模式

  3. 权衡代价:某些模式会增加代码量(如工厂模式),适合复杂场景,简单场景用反而多余。


四、现代编程中的模式演变

  • 微服务架构

    • 服务发现 → 观察者模式

    • 熔断机制 → 代理模式

  • 函数式编程

    • 策略模式 → 用函数作为参数传递(如Java的Lambda)。

  • 响应式编程

    • 数据流处理 → 责任链模式 + 观察者模式


总结

  • 设计模式是工具,不是银弹,核心是封装变化分离关注点

  • 编程思想是内功,帮助你写出更灵活、可维护的代码。

  • 结合具体场景灵活运用,才能真正掌握设计模式的精髓!

你可能感兴趣的:(设计模式,后端)