设计模式是软件开发中的"武功秘籍",它总结了前辈们在解决特定问题时积累的最佳实践。今天我们就用最通俗易懂的方式,来聊聊Java中那些常用的设计模式。
一、设计模式是什么?
想象你要装修房子:
-
没有设计模式:每次装修都从零开始,容易犯错
-
使用设计模式:有现成的装修方案模板,比如"客厅怎么装""卧室怎么布局"
设计模式就是软件开发的"装修模板",它帮我们:
-
解决常见问题
-
提高代码复用性
-
让代码更易维护
-
促进团队沟通
二、单例模式:独一无二的对象
场景:整个程序只需要一个对象,比如配置管理器、数据库连接池
public class AppConfig {
// 1. 私有静态实例
private static AppConfig instance;
// 2. 私有构造方法
private AppConfig() {}
// 3. 全局访问点
public static AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
}
// 使用
AppConfig config = AppConfig.getInstance();
特点:
-
一个类只有一个实例
-
自行创建这个实例
-
向整个系统提供这个实例
典型应用:
-
配置管理器
-
数据库连接池
-
日志系统
演进历程:
-
饿汉式(类加载时初始化)
-
懒汉式(首次使用时初始化)
-
双重检查锁定(解决线程安全问题)
-
静态内部类(利用类加载机制保证线程安全)
-
枚举实现(防止反射攻击)
注意事项:
-
多线程环境下需要加锁
-
考虑使用枚举实现更安全的单例
三、工厂模式:对象的流水线
场景:创建对象的过程比较复杂,或者需要根据不同条件创建不同对象
3.1 简单工厂
public class AnimalFactory {
public Animal createAnimal(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
}
return null;
}
}
// 使用
AnimalFactory factory = new AnimalFactory();
Animal dog = factory.createAnimal("dog");
3.2 工厂方法模式
public interface AnimalFactory {
Animal createAnimal();
}
public class DogFactory implements AnimalFactory {
public Animal createAnimal() {
return new Dog();
}
}
// 使用
AnimalFactory factory = new DogFactory();
Animal dog = factory.createAnimal();
优点:
-
将对象创建与使用分离
-
方便扩展新的产品类型
-
代码更清晰易维护
3.2 抽象工厂模式(Abstract Factory)
与工厂方法对比:
-
工厂方法:创建单一产品
-
抽象工厂:创建产品族
// 抽象工厂接口
public interface GUIFactory {
Button createButton();
TextField createTextField();
}
// 具体工厂
public class WindowsFactory implements GUIFactory {
public Button createButton() { return new WindowsButton(); }
public TextField createTextField() { return new WindowsTextField(); }
}
应用场景:
-
跨平台UI组件
-
数据库访问抽象
-
游戏角色装备系统
四、观察者模式:消息通知系统
场景:当一个对象状态改变时,需要自动通知其他对象
// 观察者接口
public interface Observer {
void update(String message);
}
// 被观察者
public class NewsAgency {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void notifyObservers(String news) {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// 具体观察者
public class NewsChannel implements Observer {
public void update(String news) {
System.out.println("收到新闻:" + news);
}
}
// 使用
NewsAgency agency = new NewsAgency();
agency.addObserver(new NewsChannel());
agency.notifyObservers("Java 17发布啦!");
现实类比:
-
微信公众号(被观察者)
-
订阅用户(观察者)
-
新文章发布(状态变化)
-
推送通知(update调用)
五、策略模式:随时切换的算法
场景:需要在运行时选择不同的算法或行为
// 策略接口
public interface PaymentStrategy {
void pay(int amount);
}
// 具体策略
public class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("信用卡支付:" + amount);
}
}
public class AlipayPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("支付宝支付:" + amount);
}
}
// 上下文
public class ShoppingCart {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void checkout(int amount) {
strategy.pay(amount);
}
}
// 使用
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new AlipayPayment());
cart.checkout(100);
优点:
-
算法可以自由切换
-
避免使用多重条件判断
-
扩展新的策略很容易
六、装饰器模式:给对象穿衣服
场景:需要动态地给对象添加功能
// 基础接口
public interface Coffee {
double getCost();
String getDescription();
}
// 具体组件
public class SimpleCoffee implements Coffee {
public double getCost() {
return 10;
}
public String getDescription() {
return "普通咖啡";
}
}
// 装饰器基类
public abstract class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
public double getCost() {
return decoratedCoffee.getCost();
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
}
// 具体装饰器
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
public double getCost() {
return super.getCost() + 2;
}
public String getDescription() {
return super.getDescription() + ",加牛奶";
}
}
// 使用
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " 价格:" + coffee.getCost());
输出:
普通咖啡,加牛奶 价格:12.0
特点:
-
比继承更灵活
-
可以动态添加/删除功能
-
避免子类爆炸
设计要点:
-
装饰器和被装饰对象实现相同接口
-
装饰器持有被装饰对象的引用
-
可以在运行时动态添加功能
与继承对比:
特性 | 继承 | 装饰器模式 |
---|---|---|
扩展方式 | 静态编译时 | 动态运行时 |
功能组合 | 需要创建子类 | 任意组合装饰器 |
类数量 | 容易导致类爆炸 | 按需创建装饰器 |
七、设计模式基础认知
7.1 设计模式起源与发展
设计模式的概念最早由建筑师Christopher Alexander提出,后由"四人帮"(GoF)在1994年出版的《设计模式:可复用面向对象软件的基础》一书中引入软件开发领域。该书系统性地总结了23种经典设计模式,这些模式至今仍是软件开发的基石。
7.2 设计模式的三大类别
创建型模式(5种)
作用:处理对象创建机制,增加系统灵活性
-
单例模式
-
工厂方法模式
-
抽象工厂模式
-
建造者模式
-
原型模式
结构型模式(7种)
作用:关注类和对象的组合方式
-
适配器模式
-
装饰器模式
-
代理模式
-
外观模式
-
桥接模式
-
组合模式
-
享元模式
行为型模式(11种)
作用:管理对象间的交互和职责分配
-
策略模式
-
观察者模式
-
责任链模式
-
命令模式
-
迭代器模式
-
状态模式
-
模板方法模式
-
访问者模式
-
备忘录模式
-
中介者模式
-
解释器模式
7.3 设计模式的六大原则
-
开闭原则:对扩展开放,对修改关闭
-
单一职责:一个类只负责一个功能领域
-
里氏替换:子类必须能替换父类
-
依赖倒置:依赖抽象而非具体实现
-
接口隔离:使用多个专用接口
-
迪米特法则:最少知识原则
八、设计模式使用建议
-
不要过度设计:简单问题不需要复杂模式
-
理解优于套用:先理解问题,再选择模式
-
组合使用:实际项目往往是多个模式组合
-
保持灵活:根据项目演进调整设计
九、快速记忆口诀
模式名称 | 一句话总结 | 生活例子 |
---|---|---|
单例模式 | 保证只有一个实例 | 公司CEO |
工厂模式 | 专门负责生产对象 | 汽车工厂 |
观察者 | 状态变化自动通知 | 微信订阅 |
策略 | 自由切换算法 | 支付方式 |
装饰器 | 动态添加功能 | 给手机加壳 |
记住:设计模式不是银弹,而是工具箱里的工具。用对场景才是关键!