我们用一种“人间清醒”的方式来聊聊Java设计模式。你会发现,它们不是高深莫测的理论,而是前辈程序员们总结出来的“最佳拍档秘籍”。
第一章:设计模式是啥?为啥要学?
想象一下,你要装修房子。 你不会每次装修都从“如何制造一颗钉子”开始吧?你会直接去宜家或者建材市场,选择现成的、设计好的家具模板,比如一个“比利”书柜或一个“马尔姆”床架。这些模板是经过无数家庭验证的,知道怎么设计最稳固、最实用、最美观。 设计模式就是软件世界里的“家具模板”。 它们不是现成的代码库,而是一套被反复验证的、针对特定问题的优秀代码设计经验总结。 为什么要学?
- 避免重复造轮子:遇到经典问题,直接用成熟方案,省时省力。
- 代码更优雅、更易维护:用上设计模式的代码,就像用了宜家模块化家具的家,结构清晰,后期要换个“沙发”(修改功能)很容易,不会牵一发动全身。
- 便于沟通:你只要说“这里我们用了个‘观察者模式’”,所有懂行的同事立刻就能明白你的设计意图,沟通成本极低。
第二章:三大派别,各有神通
设计模式经典著作《设计模式》中总结了23种模式,分为三大类,我们用公司部门来类比:
| 类型 | 核心关注点 | 好比公司里的… | 经典模式举例 |
|---|---|---|---|
| 创建型模式 | 解决“对象创建”的难题,让创建对象更灵活 | HR招聘部门:负责用不同方式(校招、社招、猎头)“创建”员工对象 | 单例、工厂、建造者 |
| 结构型模式 | 解决“类与对象组合”的难题,搭建清晰稳定的结构 | 架构部/行政部:设计部门架构(组合),提供统一接口(适配) | 适配器、装饰者、代理 |
| 行为型模式 | 解决“对象间通信”的难题,让对象各司其职又高效协作 | 工作流与沟通机制:如何分配任务(责任链),如何发布通知(观察者) | 观察者、策略、责任链 |
第三章:快速掌握几个最常用的模式
我们挑几个最实用、最能体现思想的模式来“尝尝鲜”。
模式一:单例模式 —— 皇帝的“独一无二”
生活场景:一个国家只能有一个皇帝,一个公司只能有一个CEO。 代码问题:有些对象,比如数据库连接池、配置文件管理器、日志工具,整个程序里只需要一个实例。搞出多个实例既浪费资源,又可能导致状态混乱。 单例模式的做法:保证一个类只有一个实例,并提供一个全局访问点。 Java代码(饿汉式,最简单的一种):
public class Emperor {
// 1. 私有静态实例,类加载时就创建好(所以叫“饿汉”)
private static final Emperor instance = new Emperor();
// 2. 私有构造方法,堵死外界用`new`创建实例的路!
private Emperor() {
System.out.println("我是唯一的皇帝!");
}
// 3. 公共的静态方法,供外界获取这个唯一实例
public static Emperor getInstance() {
return instance;
}
public void rule() {
System.out.println("朕即天下!");
}
}
// 使用方式
public class Kingdom {
public static void main(String[] args) {
// Emperor e = new Emperor(); // 错误!构造方法是私有的。
// 正确方式:通过getInstance获取唯一实例
Emperor emperor1 = Emperor.getInstance();
Emperor emperor2 = Emperor.getInstance();
emperor1.rule(); // 输出:朕即天下!
// 验证是否是同一个对象
System.out.println(emperor1 == emperor2); // 输出:true,是同一个对象!
}
}
核心思想:把构造器“关起来”(私有化),只留一个“门”(getInstance方法)获取唯一对象。
模式二:工厂模式 —— 专业的“代工厂”
生活场景:你想买一辆车。你不会自己去炼钢、造轮胎、组装,你会直接去“宝马4S店”或“奔驰4S店”告诉销售:“我要一辆SUV”。4S店会帮你把车造好、配置好,你直接提车就行。 代码问题:在代码中,当你需要创建一个对象时,如果创建过程很复杂(比如依赖很多配置),或者你希望创建逻辑与使用逻辑分离(使用者不关心对象怎么来的),就可以用工厂模式。 工厂模式的做法:定义一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 Java代码:
// 1. 产品接口:车
interface Car {
void drive();
}
// 2. 具体产品:宝马和奔驰
class BMW implements Car {
@Override
public void drive() {
System.out.println("开宝马...");
}
}
class Benz implements Car {
@Override
public void drive() {
System.out.println("开奔驰...");
}
}
// 3. 核心:工厂接口
interface CarFactory {
Car createCar(); // 工厂的核心职责:造车
}
// 4. 具体工厂:宝马工厂和奔驰工厂
class BMWFactory implements CarFactory {
@Override
public Car createCar() {
// 这里可能有很多复杂的制造逻辑
return new BMW();
}
}
class BenzFactory implements CarFactory {
@Override
public Car createCar() {
return new Benz();
}
}
// 使用方式:客户买车
public class Customer {
public static void main(String[] args) {
// 要去宝马4S店
CarFactory factory = new BMWFactory();
Car myCar = factory.createCar(); // 告诉4S店:给我造一辆
myCar.drive(); // 输出:开宝马...
// 换一家店
factory = new BenzFactory();
myCar = factory.createCar();
myCar.drive(); // 输出:开奔驰...
}
}
核心思想:将“对象创建”这个动作抽象出来,与“对象使用”分离开。使用者只面对抽象接口(Car和CarFactory),不关心具体实现,非常符合“依赖倒置”原则,大大提升了代码的灵活性。
模式三:观察者模式 —— 微信公众号的“订阅-通知”机制
生活场景:你关注了一个微信公众号(成为观察者)。当公众号发布新文章时(被观察者状态改变),所有关注者都会收到推送通知。 代码问题:当一个对象(目标对象)的状态发生改变时,如何自动通知所有依赖它的对象(观察者对象),并且这些对象之间是松耦合的? 观察者模式的做法:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 Java代码(Java自身就提供了java.util.Observer接口,但我们这里手写一个更直观):
import java.util.ArrayList;
import java.util.List;
// 1. 被观察者/主题 (Subject) - 好比微信公众号平台
class WeChatOfficialAccount {
private String name;
private String latestArticle; // 状态:最新文章
private List<Follower> followers = new ArrayList<>(); // 维护所有观察者
public WeChatOfficialAccount(String name) {
this.name = name;
}
// 核心方法:发布新文章
public void publishArticle(String articleTitle) {
this.latestArticle = articleTitle;
System.out.println(name + " 发布了新文章:《" + articleTitle + "》");
notifyAllFollowers(); // 状态改变,通知所有观察者!
}
// 供观察者订阅和取消订阅
public void addFollower(Follower follower) {
followers.add(follower);
}
public void removeFollower(Follower follower) {
followers.remove(follower);
}
// 通知所有的观察者
private void notifyAllFollowers() {
for (Follower follower : followers) {
follower.update(this.name, this.latestArticle); // 调用观察者的更新方法
}
}
}
// 2. 观察者接口 (Observer) - 定义粉丝应有的行为
interface Follower {
void update(String accountName, String articleTitle); // 收到通知后更新自己
}
// 3. 具体观察者 (ConcreteObserver) - 真实的粉丝
class User implements Follower {
private String userName;
public User(String userName) {
this.userName = userName;
}
@Override
public void update(String accountName, String articleTitle) {
// 每个粉丝收到通知后的反应
System.out.println("【" + userName + "】收到通知:公众号【" + accountName + "】有新文章《" + articleTitle + "》可阅读!");
}
}
// 使用方式
public class WeChatWorld {
public static void main(String[] args) {
// 创建公众号(被观察者)
WeChatOfficialAccount account = new WeChatOfficialAccount("全栈编程宝典");
// 创建用户(观察者)
User userA = new User("小明");
User userB = new User("小红");
// 用户关注公众号
account.addFollower(userA);
account.addFollower(userB);
// 公众号发布文章 -> 自动通知所有关注者
account.publishArticle("设计模式其实很简单");
System.out.println("---------------");
// 小红取关
account.removeFollower(userB);
// 再发布文章,只有小明能收到
account.publishArticle("Java并发编程实战");
}
}
核心思想:解耦!被观察者只负责维护一个观察者列表并在状态改变时通知,它不关心观察者具体是谁、做了什么。观察者则负责在收到通知后采取行动。双方通过接口耦合,职责清晰。
给你的学习路线图
- 理解思想,而非背诵代码:永远记住每个模式要解决什么痛点。先问“为什么”,再看“怎么做”。
- 从常用模式开始:
- 创建型:重点掌握 单例(Singleton)、工厂方法(Factory Method)。
- 结构型:重点掌握 适配器(Adapter)、装饰者(Decorator)。
- 行为型:重点掌握 观察者(Observer)、策略(Strategy)。
- 结合项目思考:在看代码或自己写代码时,有意识地想:“这里是不是可以用某个设计模式来优化?”
- 不要过度设计!设计模式是“利器”,但不是“银弹”。如果业务逻辑很简单,直接
new一个对象就完事了,非要用上工厂模式反而把简单问题复杂化。
总结
设计模式就是编程界的“孙子兵法”或“棋谱定式”,是前人智慧的结晶。你现在可能觉得有点抽象,这非常正常! 最好的学习方式就是:
- 看懂上面的例子。
- 自己动手敲一遍。
- 尝试在你自己的小项目中找一个地方用上去(比如,用单例模式管理你的配置类)。
当你真正用模式解决了一个实际问题后,你就会豁然开朗,真正理解它的妙处。加油!有任何问题随时再来问我。




