Java 常见设计模式详解:从理论到代码实现
·
目录
一、单例模式(Singleton Pattern)
【1】核心思想
保证一个类仅有一个实例,并提供一个全局访问点。
【2】适用场景
- 配置文件管理器
- 日志工具类
- 线程池、连接池等资源管理器
【3】实现方式:双重检查锁(线程安全)
public class Singleton {
// volatile 防止指令重排序
private static volatile volatile Singleton instance;
// 私有构造方法,防止外部实例化
private Singleton() {}
// 双重检查锁实现
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
【4】优点
- 节省系统资源,避免频繁创建销毁对象
- 全局唯一实例,便于协调系统行为
二、工厂模式(Factory Pattern)
【1】核心思想
定义一个创建对象的接口,让子类的子类决定实例化哪个类,使实例化延迟到子类。
【2】适用场景
- 对象创建逻辑复杂,需要集中管理
- 需要根据不同条件创建不同类型的对象
- 解耦对象的创建和使用
【3】实现方式:简单工厂模式
// 产品接口
public interface Shape {
void draw();
}
// 具体产品
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("画圆形");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画矩形");
}
}
// 工厂类
public class ShapeFactory {
// 根据类型创建对应对象
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
}
return null;
}
}
// 使用示例
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
Shape shape1 = shapeFactory.getShape("CIRCLE");
shape1.draw(); // 输出:画圆形
Shape shape2 = shapeFactory.getShape("RECTANGLE");
shape2.draw(); // 输出:画矩形
}
}
【4】优点
- 降低代码耦合度,符合开闭原则
- 便于扩展,新增产品只需添加新的实现类和工厂逻辑
三、观察者模式(Observer Pattern)
【1】核心思想
定义对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知并自动更新。
【2】适用场景
- 事件监听机制
- 消息通知系统
- 实时数据展示(如股票行情)
【3】实现方式
import java.util.ArrayList;
import java.util.List;
// 主题接口
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 观察者接口
public interface Observer {
void update(String message);
}
// 具体主题
public class NewsSubject implements Subject {
private List<Observer> observers;
private String message;
public NewsSubject() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
// 发布新闻
public void setNews(String news) {
this.message = news;
notifyObservers(); // 通知所有观察者
}
}
// 具体观察者
public class UserObserver implements Observer {
private String name;
public UserObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " 收到新闻:" + message);
}
}
// 使用示例
public class ObserverPatternDemo {
public static void main(String[] args) {
NewsSubject newsSubject = new NewsSubject();
Observer user1 = new UserObserver("张三");
Observer user2 = new UserObserver("李四");
newsSubject.registerObserver(user1);
newsSubject.registerObserver(user2);
newsSubject.setNews("Java 设计模式详解发布啦!");
// 输出:
// 张三 收到新闻:Java 设计模式详解发布啦!
// 李四 收到新闻:Java 设计模式详解发布啦!
}
}
【4】优点
- 实现观察者与被观察者解耦
- 支持动态添加和移除观察者
四、装饰器模式(Decorator Pattern)
【1】核心思想
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更灵活。
【2】适用场景
- 需要动态扩展类的功能,且不影响其他对象
- 不适合通过继承实现的场景(如继承层次过深)
【3】实现方式
// 抽象组件
public interface Beverage {
String getDescription();
double cost();
}
// 具体组件
public class Coffee implements Beverage {
@Override
public String getDescription() {
return "黑咖啡";
}
@Override
public double cost() {
return 20.0;
}
}
// 装饰器抽象类
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription();
}
}
// 具体装饰器
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ",加牛奶";
}
@Override
public double cost() {
return beverage.cost() + 5.0;
}
}
public 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;
}
}
// 使用示例
public class DecoratorPatternDemo {
public static void main(String[] args) {
// 基础咖啡
Beverage beverage = new Coffee();
System.out.println(beverage.getDescription() + " 价格:" + beverage.cost());
// 加牛奶的咖啡
Beverage milkCoffee = new Milk(new Coffee());
System.out.println(milkCoffee.getDescription() + " 价格:" + milkCoffee.cost());
// 加牛奶和糖的咖啡
Beverage milkSugarCoffee = new Sugar(new Milk(new Coffee()));
System.out.println(milkSugarCoffee.getDescription() + " 价格:" + milkSugarCoffee.cost());
}
}
【4】优点
- 可以灵活组合功能,避免类爆炸
- 符合开闭原则,扩展方便
五、策略模式(Strategy Pattern)
【1】核心思想
定义一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
【2】适用场景
- 多个类只有算法或行为不同的场景
- 需要动态切换算法的场景
- 避免使用多重条件判断(if-else/switch)
【3】实现方式
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略
public class AliPayStrategy implements PaymentStrategy {
private String username;
public AliPayStrategy(String username) {
this.username = username;
}
@Override
public void pay(double amount) {
System.out.println(username + " 使用支付宝支付了 " + amount + " 元");
}
}
public class WechatPayStrategy implements PaymentStrategy {
private String phoneNumber;
public WechatPayStrategy(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public void pay(double amount) {
System.out.println(phoneNumber + " 使用微信支付了 " + amount + " 元");
}
}
// 上下文类
public class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(double amount) {
paymentStrategy.pay(amount);
}
}
// 使用示例
public class StrategyPatternDemo {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
// 选择支付宝支付
cart.setPaymentStrategy(new AliPayStrategy("zhangsan@example.com"));
cart.checkout(199.9);
// 切换为微信支付
cart.setPaymentStrategy(new WechatPayStrategy("13800138000"));
cart.checkout(299.5);
}
}
【4】优点
- 算法可以自由切换
- 避免使用多重条件判断
- 扩展性良好,新增算法只需实现接口
六、适配器模式(Adapter Pattern)
【1】核心思想
将一个类的接口转换成客户端希望的另一个接口,使原本因接口不兼容而无法一起工作的类可以协同工作。
【2】适用场景
- 集成第三方组件,但其接口与现有系统不匹配
- 重构旧系统时,需要兼容新的接口规范
- 统一多个类的接口,便于客户端调用
【3】实现方式:对象适配器
// 目标接口(客户端期望的接口)
public interface Target {
void request();
}
// 适配者(需要被适配的类)
public class Adaptee {
// 适配者的特定方法
public void specificRequest() {
System.out.println("执行适配者的业务逻辑");
}
}
// 适配器类
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
// 适配过程:将目标接口的方法转换为适配者的方法
adaptee.specificRequest();
}
}
// 使用示例
public class AdapterPatternDemo {
public static void main(String[] args) {
// 创建适配者对象
Adaptee adaptee = new Adaptee();
// 创建适配器,包装适配者
Target target = new Adapter(adaptee);
// 客户端通过目标接口调用,实际执行的是适配者的逻辑
target.request();
}
}
【4】优点
- 解决接口不兼容问题,提高代码复用性
- 无需修改原有代码,符合开闭原则
- 灵活性高,可动态切换不同的适配者
七、代理模式(Proxy Pattern)
【1】核心思想
为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。
【2】适用场景
- 远程代理:如 RPC 框架中代理远程服务
- 安全代理:控制对敏感对象的访问权限
- 延迟加载:在需要时才初始化目标对象(如 Hibernate 的懒加载)
- 日志记录:在方法调用前后记录日志
【3】实现方式:静态代理
// 主题接口
public interface Image {
void display();
}
// 真实主题(被代理对象)
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(); // 模拟从磁盘加载图片(耗时操作)
}
private void loadFromDisk() {
System.out.println("加载图片: " + fileName);
}
@Override
public void display() {
System.out.println("显示图片: " + fileName);
}
}
// 代理类
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
// 延迟初始化:只有当真正需要显示时才创建真实对象
if (realImage == null) {
realImage = new RealImage(fileName);
}
// 可以在这里添加额外逻辑,如日志记录、权限检查等
System.out.println("Proxy: 准备显示图片");
realImage.display();
System.out.println("Proxy: 显示完成");
}
}
// 使用示例
public class ProxyPatternDemo {
public static void main(String[] args) {
// 创建代理对象(此时并未加载图片)
Image image = new ProxyImage("test.jpg");
// 第一次调用display(),才会真正加载并显示图片
image.display();
System.out.println("---");
// 第二次调用,直接使用已创建的真实对象
image.display();
}
}
【4】优点
- 保护目标对象,控制访问权限
- 实现延迟加载,提高系统性能
- 便于在不修改目标对象的前提下添加额外功能(如日志、事务)
八、总结
设计模式是解决特定问题的最佳实践,掌握这些模式能帮助我们写出更优雅、可维护的代码。以上 7 种设计模式是 Java 开发中最常用的,总结如下:
单例模式:控制对象创建,适合全局资源管理
工厂模式:封装对象创建逻辑,解耦创建与使用
观察者模式:实现对象间的联动通信,适合事件驱动场景
装饰器模式:动态扩展功能,避免继承层次过深
策略模式:封装不同算法,实现灵活切换
适配器模式:解决接口不兼容问题,便于集成第三方组件
代理模式:控制对象访问,实现延迟加载和功能增强
感谢你花时间读到这里~ 如果你觉得这篇内容对你有帮助,不妨点个赞让更多人看到;如果有任何想法、疑问,或者想分享你的相关经历,欢迎在评论区留言交流,你的每一条互动对我来说都很珍贵~ 我们下次再见啦!😊😊
更多推荐
所有评论(0)