常用设计模式介绍
工厂方法模式
工厂方法设计模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种封装对象创建的方式。通过这种模式,父类将对象的创建延迟到子类中实现,从而使得基类或接口的代码与具体实现解耦。
工厂方法设计模式的核心思想:
-
定义一个用于创建对象的接口,但让实现这个接口的类决定实例化哪一个类。
-
工厂方法让类的实例化推迟到子类,这样客户端代码只需要依赖于抽象接口,而无需关注具体的实现细节。
举个例子: 场景描述: 假设我们有一个"支付系统",用户可以选择使用不同的支付方式(例如:支付宝、微信支付、银行卡等)。我们需要根据用户的输入来创建对应的支付对象,并调用其支付功能。
-
定义产品接口 首先,定义一个通用的支付接口 Payment,所有的具体支付方式都必须实现这个接口。
javapublic interface Payment { void pay(double amount); }
-
具体产品类 接着,实现两个具体的支付方式:支付宝和微信支付。
javapublic class Alipay implements Payment { @Override public void pay(double amount) { System.out.println("使用支付宝支付了:" + amount + "元"); } } public class WechatPay implements Payment { @Override public void pay(double amount) { System.out.println("使用微信支付了:" + amount + "元"); } }
-
定义工厂接口(可选) 为了进一步解耦,可以定义一个工厂接口 PaymentFactory,它声明了一个工厂方法 createPayment()。
javapublic interface PaymentFactory { Payment createPayment(); }
-
具体工厂类 每个具体工厂类负责创建对应的具体产品。
javapublic class AlipayFactory implements PaymentFactory { @Override public Payment createPayment() { return new Alipay(); } } public class WechatPayFactory implements PaymentFactory { @Override public Payment createPayment() { return new WechatPay(); } }
-
使用示例 在客户端代码中,我们可以根据用户的选择动态地选择支付方式。
javapublic class Client { public static void main(String[] args) { // 假设用户选择了支付宝支付 PaymentFactory factory = new AlipayFactory(); Payment payment = factory.createPayment(); payment.pay(100.0); // 如果需要切换为微信支付,只需更换工厂 factory = new WechatPayFactory(); payment = factory.createPayment(); payment.pay(200.0); } }
工厂方法模式的优点:
-
解耦:客户端代码只依赖于抽象接口,不直接依赖具体类,这有助于降低模块之间的耦合度。
-
扩展性好:当需要新增一种支付方式时,只需添加新的具体产品类和对应的工厂类,而不需要修改已有的代码。
-
符合开闭原则:对扩展开放,对修改关闭。
适用场景:
-
当一个类不知道它所需要的对象的具体类时。
-
当一个类希望由它的子类来指定它所创建的对象的时候。
-
当一组相关类构成一个层次结构,且每组都需要实例化其中一个类时。
总结: 工厂方法模式通过将对象的创建交给子类,实现了对象创建的灵活性和扩展性。它非常适合用于需要根据条件动态选择不同实现的场景,同时也能很好地遵循面向对象的设计原则。
装饰器模式
装饰器设计模式(Decorator Pattern)是一种结构型设计模式,它允许在不修改对象接口的前提下,动态地为对象添加新的功能。这种模式通过组合的方式扩展对象的功能,而不是通过继承来实现,因此比传统的子类化方式更加灵活。
装饰器设计模式的核心思想:
-
保持对象接口一致:装饰器类与被装饰的对象实现相同的接口,这样客户端代码可以透明地使用原始对象和装饰后的对象。
-
组合优于继承:通过将原始对象包装在装饰器中,并在其基础上增加新功能,可以避免由于多层继承导致的类爆炸问题。
-
动态增强功能:可以在运行时根据需要多次装饰一个对象,从而逐步增强其行为
举个例子: 场景描述: 假设我们有一个简单的文本消息处理系统,我们需要对文本进行不同的修饰操作,例如加密、压缩、格式化等。我们可以使用装饰器模式来实现这些功能。
-
定义组件接口 首先定义一个通用的消息处理接口 Message。
javapublic interface Message { String getContent(); }
-
具体组件类 创建一个基本的消息处理器 PlainTextMessage。
javapublic class PlainTextMessage implements Message { private String content; public PlainTextMessage(String content) { this.content = content; } @Override public String getContent() { return content; } }
-
定义装饰器抽象类 创建一个装饰器抽象类 MessageDecorator,它实现了 Message 接口,并持有一个 Message 对象的引用。
javapublic abstract class MessageDecorator implements Message { protected Message decoratedMessage; public MessageDecorator(Message decoratedMessage) { this.decoratedMessage = decoratedMessage; } @Override public String getContent() { return decoratedMessage.getContent(); } }
-
具体装饰器类 实现具体的装饰器类,例如加密装饰器 EncryptedMessageDecorator 和压缩装饰器 CompressedMessageDecorator。
javapublic class EncryptedMessageDecorator extends MessageDecorator { public EncryptedMessageDecorator(Message decoratedMessage) { super(decoratedMessage); } @Override public String getContent() { // 在原有内容的基础上进行加密处理 String originalContent = super.getContent(); return encrypt(originalContent); } private String encrypt(String content) { // 简单的加密逻辑(实际应用中应使用更安全的算法) return "加密后的文本: " + content.hashCode(); } } public class CompressedMessageDecorator extends MessageDecorator { public CompressedMessageDecorator(Message decoratedMessage) { super(decoratedMessage); } @Override public String getContent() { // 在原有内容的基础上进行压缩处理 String originalContent = super.getContent(); return compress(originalContent); } private String compress(String content) { // 简单的压缩逻辑(实际应用中应使用更高效的压缩算法) return "压缩后的文本: " + content.substring(0, Math.min(10, content.length())) + "..."; } }
-
使用示例 在客户端代码中,我们可以根据需求动态地为消息添加加密和压缩功能。
javapublic class Client { public static void main(String[] args) { // 原始文本消息 Message message = new PlainTextMessage("这是一个测试消息"); System.out.println("原始消息: " + message.getContent()); // 加密消息 Message encryptedMessage = new EncryptedMessageDecorator(message); System.out.println("加密后的消息: " + encryptedMessage.getContent()); // 加密并压缩消息 Message compressedAndEncryptedMessage = new CompressedMessageDecorator(new EncryptedMessageDecorator(message)); System.out.println("加密并压缩后的消息: " + compressedAndEncryptedMessage.getContent()); } }
装饰器模式的优点:
-
动态扩展功能:可以在运行时根据需要动态地为对象添加功能,而不需要修改现有代码。
-
避免类爆炸:相比于通过继承来扩展功能,装饰器模式可以大大减少类的数量,避免了类爆炸问题。
-
符合开闭原则:对扩展开放,对修改关闭,新增装饰器不会影响已有代码。
适用场景:
-
当需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责时。
-
当子类扩展不再可行时(因为可能有太多组合,或者需要在运行时决定如何扩展)。
总结: 装饰器设计模式通过组合的方式,提供了一种灵活且可扩展的方式来增强对象的功能。它非常适合用于需要在运行时动态地为对象添加新功能的场景,同时也能很好地遵循面向对象的设计原则。
适配器模式
适配器设计模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端期望的另一个兼容接口。适配器模式常用于解决已有类与目标接口不兼容的问题,使得原本由于接口不匹配而无法协同工作的类能够一起工作。
适配器模式的核心思想:
-
接口转换:通过创建一个适配器类,将一个类的接口包装或转换为另一个接口,从而满足客户端的需求。
-
复用已有代码:无需修改现有类的实现,就可以将其集成到新的系统中。
-
组合优于继承:适配器通常会持有被适配对象的实例,并在其基础上提供适配后的接口。
适配器模式的两种实现方式:
-
类适配器(使用继承)
-
适配器类同时继承目标接口和被适配的类。
-
适用于支持多重继承的语言(如 C++),但在 Java 中由于单继承限制,这种方式不太常用。
-
-
对象适配器(使用组合)
-
适配器类实现目标接口,并持有一个被适配对象的引用。
-
更加灵活,是 Java 等语言中更常见的做法。
-
示例说明: 场景描述: 假设我们正在开发一个日志分析系统,系统希望调用一个 Logger 接口来记录日志信息。但目前我们有一个第三方库提供的 LegacyLogSystem 类,它的方法名是 logMessage(String msg),而不是我们期望的 log(String message)。我们可以使用适配器模式来解决这个接口不一致的问题。
-
定义目标接口
javapublic interface Logger { void log(String message); }
-
已有的具体类
javapublic class LegacyLogSystem { public void logMessage(String msg) { System.out.println("Legacy Log: " + msg); } }
-
创建适配器类(对象适配器)
javapublic class LoggerAdapter implements Logger { private LegacyLogSystem legacyLogSystem; public LoggerAdapter(LegacyLogSystem legacyLogSystem) { this.legacyLogSystem = legacyLogSystem; } @Override public void log(String message) { // 将目标接口的方法调用适配到 LegacyLogSystem 的方法上 legacyLogSystem.logMessage(message); } }
-
使用示例
javapublic class Client { public static void main(String[] args) { // 创建旧系统的日志对象 LegacyLogSystem legacyLogSystem = new LegacyLogSystem(); // 通过适配器将其接入新系统 Logger logger = new LoggerAdapter(legacyLogSystem); // 调用统一的日志接口 logger.log("这是一条测试日志消息"); } }
输出结果:
Legacy Log: 这是一条测试日志消息
适配器模式的优点:
-
兼容性:可以让不兼容的接口协同工作,提高系统的兼容性和可扩展性。
-
复用性:可以复用已有的类,避免重复造轮子。
-
开闭原则:增加新的适配器不会影响原有代码逻辑。
适用场景:
-
当你想使用一个已经存在的类,但它的接口不符合你的需求时。
-
当你希望在不修改现有代码的前提下,让多个不同接口的类协同工作时。
-
当你需要对多个类进行统一接口封装时。
总结: 适配器设计模式是一种非常实用的设计模式,尤其适用于系统集成和遗留系统改造。通过适配器,我们可以轻松地将不同接口的类整合在一起,使得系统更加灵活、可维护和可扩展
策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。策略模式让算法的变化独立于使用它的客户端,从而实现动态切换行为的目的。
策略模式的核心思想:
-
封装变化:将一组相似的行为(如算法、策略)封装为不同的类。
-
多态调用:客户端通过统一接口来调用这些策略,达到运行时动态切换的效果。
-
解耦逻辑:避免在业务代码中使用大量的 if-else 或 switch-case 来判断不同策略。
示例说明: 场景描述: 我们继续以"支付系统"为例。用户可以选择多种支付方式(如支付宝、微信支付、银行卡等),每种支付方式有不同的验证和执行流程。我们可以使用策略模式来实现这个场景。
-
定义策略接口 首先定义一个通用的支付策略接口 PaymentStrategy。
javapublic interface PaymentStrategy { void pay(double amount); }
-
实现具体策略类
java//支付宝支付策略 public class AlipayStrategy implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("使用支付宝支付:" + amount + "元"); } } //微信支付策略 public class WechatPayStrategy implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("使用微信支付:" + amount + "元"); } } //银行卡支付策略 public class BankCardStrategy implements PaymentStrategy { private String cardNumber; public BankCardStrategy(String cardNumber) { this.cardNumber = cardNumber; } @Override public void pay(double amount) { System.out.println("使用银行卡(尾号:" + cardNumber.substring(cardNumber.length() - 4) + ")支付:" + amount + "元"); } }
-
创建上下文类(Context) 该类用于持有当前使用的策略对象,并对外提供统一的方法供客户端调用
javapublic class PaymentContext { private PaymentStrategy paymentStrategy; public void setPaymentStrategy(PaymentStrategy paymentStrategy) { this.paymentStrategy = paymentStrategy; } public void executePayment(double amount) { paymentStrategy.pay(amount); } }
-
使用示例 客户端可以根据用户的输入动态选择不同的支付方式。
javapublic class Client { public static void main(String[] args) { PaymentContext context = new PaymentContext(); // 用户选择支付宝支付 context.setPaymentStrategy(new AlipayStrategy()); context.executePayment(100.0); // 用户选择微信支付 context.setPaymentStrategy(new WechatPayStrategy()); context.executePayment(200.0); // 用户选择银行卡支付 context.setPaymentStrategy(new BankCardStrategy("6225880123456789")); context.executePayment(300.0); } }
输出结果:
使用支付宝支付:100.0元 使用微信支付:200.0元 使用银行卡(尾号:6789)支付:300.0元
策略模式的优点:
-
可扩展性强:新增一种支付方式只需添加新的策略类,无需修改已有代码。
-
高内聚低耦合:每个策略独立封装,便于维护和测试。
-
易于替换:运行时可以根据需要动态更换策略。
适用场景:
-
当某个业务逻辑有多个变体(如支付方式、折扣策略、排序算法等),且需要在运行时动态切换时。
-
避免大量 if-else 或 switch-case 判断逻辑。
-
当希望将复杂行为从主业务逻辑中剥离出来进行独立管理时。
总结: 策略模式通过将不同的行为封装为独立的类,并通过统一接口进行调用,实现了灵活切换和良好扩展性。它非常适合用于需要根据不同条件选择不同处理逻辑的场景,是解耦和提高可维护性的有力工具。
模板方法模式
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架(即一个操作中的"固定流程"),而将一些步骤延迟到子类中去实现。这样可以在不改变算法结构的前提下,允许子类重新定义算法中的某些步骤。
模板方法模式的核心思想:
-
定义算法框架:在抽象类中定义一个 final 方法(即模板方法),该方法包含了算法的主要步骤。
-
延迟具体实现:将算法中可能变化的部分定义为抽象方法,由子类来具体实现。
-
钩子方法(可选):提供一些可选的钩子方法(hook methods),让子类可以有选择地参与算法流程。
示例说明: 场景描述: 我们以"制作咖啡和茶"为例。无论是泡咖啡还是泡茶,它们的基本步骤是相似的:
-
把水烧开
-
冲泡饮品
-
倒入杯子
-
添加调料(如糖或牛奶)
但每一步的具体实现会有所不同,我们可以使用模板方法模式来统一这个流程。
-
定义抽象类(模板类)
javapublic abstract class Beverage { // 模板方法:定义算法骨架 public final void prepareBeverage() { boilWater(); brew(); pourInCup(); addCondiments(); } // 公共方法:所有饮料都需要执行的操作 private void boilWater() { System.out.println("烧开水"); } private void pourInCup() { System.out.println("倒入杯中"); } // 抽象方法:需要子类实现 protected abstract void brew(); protected abstract void addCondiments(); }
-
创建具体子类
java//咖啡类 public class Coffee extends Beverage { @Override protected void brew() { System.out.println("用滤纸冲泡咖啡"); } @Override protected void addCondiments() { System.out.println("添加糖和牛奶"); } } //茶类 public class Tea extends Beverage { @Override protected void brew() { System.out.println("用热水泡茶叶"); } @Override protected void addCondiments() { System.out.println("添加柠檬片"); } }
csharp
3. 使用示例
```java
public class Client {
public static void main(String[] args) {
System.out.println("准备一杯咖啡:");
Beverage coffee = new Coffee();
coffee.prepareBeverage();
System.out.println("\n准备一杯茶:");
Beverage tea = new Tea();
tea.prepareBeverage();
}
}
输出结果:
准备一杯咖啡: 烧开水 用滤纸冲泡咖啡 倒入杯中 添加糖和牛奶
准备一杯茶: 烧开水 用热水泡茶叶 倒入杯中 添加柠檬片
模板方法模式的优点:
-
代码复用性高:将公共逻辑封装在父类中,避免重复代码。
-
扩展性强:新增子类时只需重写特定步骤,而不影响整体流程。
-
符合开闭原则:对扩展开放,对修改关闭。
-
控制流程一致性:确保算法结构不变,避免子类破坏流程顺序。
钩子方法(Hook Method)的扩展: 你还可以在模板类中加入钩子方法,让子类决定是否执行某个步骤。例如:
java
protected boolean customerWantsCondiments() {
return true;
}
然后在模板方法中判断是否调用添加调料的方法:
java
if (customerWantsCondiments()) {
addCondiments();
}
子类可以选择覆盖这个钩子方法来决定是否添加调料。
适用场景:
-
当多个类有相似的算法结构,但具体实现细节不同时。
-
当希望统一控制算法流程,防止子类破坏流程逻辑时。
-
当希望减少重复代码并提高可维护性时。
总结: 模板方法模式通过在抽象类中定义算法骨架,并将具体实现延迟到子类中,实现了良好的封装性和扩展性。它是实现"算法复用 + 行为定制"的一种非常有效的方式,广泛应用于框架设计、业务流程标准化等场景
责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它将请求的发送者和接收者解耦,并通过一个对象链来处理请求。每个处理者对象在接收到请求后,可以选择自己处理、转发给下一个处理者或者直接丢弃请求。
责任链模式的核心思想:
-
请求的传递链:多个处理器构成一条链,请求从链的一端发起,沿着链依次传递。
-
动态处理流程:每个处理器决定是否处理请求或将其传递给下一个处理器。
-
解耦请求与处理逻辑:客户端不需要知道具体由谁处理,只需要将请求发到链上即可。
示例说明: 场景描述: 我们以"审批流程"为例。例如员工提交请假申请,根据请假天数不同,审批人也不同:
-
1~3天:主管审批
-
4~7天:部门经理审批
-
8天以上:总经理审批
我们可以使用责任链模式实现这个流程。
-
定义抽象处理类
javapublic abstract class Approver { protected Approver nextApprover; public void setNextApprover(Approver nextApprover) { this.nextApprover = nextApprover; } public abstract void approve(int days); }
-
实现具体的处理类
java//主管审批类 public class TeamLeaderApprover extends Approver { @Override public void approve(int days) { if (days <= 3) { System.out.println("主管审批了 " + days + " 天的请假"); } else if (nextApprover != null) { System.out.println("主管无权审批,转交下一级..."); nextApprover.approve(days); } } } //部门经理审批类 public class DepartmentManagerApprover extends Approver { @Override public void approve(int days) { if (days > 3 && days <= 7) { System.out.println("部门经理审批了 " + days + " 天的请假"); } else if (nextApprover != null) { System.out.println("部门经理无权审批,转交下一级..."); nextApprover.approve(days); } } } //总经理审批类 public class CEOApprover extends Approver { @Override public void approve(int days) { if (days > 7) { System.out.println("总经理审批了 " + days + " 天的请假"); } else if (nextApprover != null) { nextApprover.approve(days); } else { System.out.println("没有合适的审批人,请假申请被拒绝"); } } }
-
使用示例
javapublic class Client { public static void main(String[] args) { // 构建审批责任链 Approver teamLeader = new TeamLeaderApprover(); Approver departmentManager = new DepartmentManagerApprover(); Approver ceo = new CEOApprover(); teamLeader.setNextApprover(departmentManager); departmentManager.setNextApprover(ceo); // 模拟不同天数的请假申请 System.out.println("请假1天:"); teamLeader.approve(1); System.out.println("\n请假5天:"); teamLeader.approve(5); System.out.println("\n请假10天:"); teamLeader.approve(10); } }
输出结果:
请假1天: 主管审批了 1 天的请假
请假5天: 主管无权审批,转交下一级... 部门经理审批了 5 天的请假
请假10天: 主管无权审批,转交下一级... 部门经理无权审批,转交下一级... 总经理审批了 10 天的请假
责任链模式的优点:
优点 | 描述 |
---|---|
解耦请求与处理 | 请求发送者不需要知道具体的处理者是谁,只需把请求发到链上。 |
可扩展性强 | 可以灵活地增加或修改处理节点,符合开闭原则。 |
职责清晰 | 每个处理者只负责自己的业务逻辑,便于维护和测试。 |
支持动态流程 | 可在运行时根据条件构建不同的处理链路。 |
适用场景:
-
工作流审批系统(如报销、请假、采购等)
-
过滤器/拦截器机制(如 Spring 中的 HandlerInterceptor)
-
日志处理(如按级别过滤日志输出)
总结: 责任链模式非常适合用于多级判断处理的场景,它让请求处理流程更加清晰、灵活。通过将处理逻辑拆分为独立的节点,不仅提高了系统的可扩展性,也增强了代码的可读性和可维护性。
单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类在整个应用程序生命周期中只有一个实例存在,并提供一个全局访问点来获取这个实例。
单例模式的核心思想:
-
私有构造方法:防止外部通过 new 关键字创建多个实例。
-
静态私有实例:在类内部维护一个唯一的实例。
-
公共静态方法:对外提供获取该唯一实例的方法
优点:
优点 | 描述 |
---|---|
资源节约 | 避免频繁创建和销毁对象,节省系统资源。 |
全局访问 | 提供统一的访问入口,便于共享数据或服务。 |
控制实例数量 | 保证在整个程序中某个类只有一个实例,避免冲突 |
示例说明: 场景描述: 我们以"数据库连接池"为例。数据库连接是一种有限资源,通常希望在整个系统中只使用一个连接池管理器,这样可以统一管理和调度连接。
-
简单懒汉式单例(线程不安全)
javapublic class DatabaseConnection { // 私有静态实例 private static DatabaseConnection instance; // 私有构造方法 private DatabaseConnection() { System.out.println("数据库连接池初始化..."); } // 公共静态方法获取实例 public static DatabaseConnection getInstance() { if (instance == null) { instance = new DatabaseConnection(); } return instance; } public void connect() { System.out.println("连接到数据库"); } }
⚠️ 缺点:在多线程环境下可能创建多个实例。
-
懒汉式 + 同步方法(线程安全)
javapublic class DatabaseConnection { private static DatabaseConnection instance; private DatabaseConnection() { System.out.println("数据库连接池初始化..."); } // 加同步锁保证线程安全 public static synchronized DatabaseConnection getInstance() { if (instance == null) { instance = new DatabaseConnection(); } return instance; } public void connect() { System.out.println("连接到数据库"); } }
✅ 优点:线程安全
⚠️ 缺点:每次调用 getInstance() 都需要加锁,性能较差。
- 双重检查锁定(Double-Checked Locking)
java
public class DatabaseConnection {
// 使用 volatile 保证多线程可见性
private static volatile DatabaseConnection instance;
private DatabaseConnection() {
System.out.println("数据库连接池初始化...");
}
public static DatabaseConnection getInstance() {
if (instance == null) {
synchronized (DatabaseConnection.class) {
if (instance == null) {
instance = new DatabaseConnection();
}
}
}
return instance;
}
public void connect() {
System.out.println("连接到数据库");
}
}
✅ 推荐方式,兼顾性能与线程安全。
- 饿汉式单例(类加载时就初始化)
java
public class DatabaseConnection {
// 类加载时就初始化
private static final DatabaseConnection INSTANCE = new DatabaseConnection();
private DatabaseConnection() {
System.out.println("数据库连接池初始化...");
}
public static DatabaseConnection getInstance() {
return INSTANCE;
}
public void connect() {
System.out.println("连接到数据库");
}
}
✅ 线程安全,简单高效
⚠️ 缺点:不管是否使用都会初始化,造成资源浪费。
-
枚举实现单例(推荐方式)
javapublic enum DatabaseConnectionEnum { INSTANCE; public void connect() { System.out.println("连接到数据库"); } }
✅ 最安全的方式,防止反射攻击、序列化破坏单例
✅ 天然支持线程安全和反序列化机制
使用示例:
java
public class Client {
public static void main(String[] args) {
DatabaseConnection conn1 = DatabaseConnection.getInstance();
DatabaseConnection conn2 = DatabaseConnection.getInstance();
System.out.println("conn1 == conn2: " + (conn1 == conn2)); // 输出 true
conn1.connect();
}
}
输出结果:
数据库连接池初始化... conn1 == conn2: true 连接到数据库
适用场景:
-
日志记录器(如日志文件只能有一个写入者)
-
缓存管理器(如 Redis 连接池)
-
线程池管理器
-
配置管理器(如读取配置文件后缓存配置信息)
注意事项:
问题 | 建议 |
---|---|
多线程安全 | 使用双重检查锁定或枚举实现 |
反射攻击 | 使用枚举或在构造函数中加判断防止多次创建 |
序列化/反序列化破坏单例 | 使用枚举或自定义 readResolve() 方法 |
过度使用 | 避免滥用单例,可能导致代码难以测试和扩展 |
总结: 单例模式是应用最广泛的设计模式之一,适用于需要全局唯一实例的场景。虽然实现方式多样,但推荐使用双重检查锁定或枚举实现,既能保证线程安全,又能防止反射和序列化带来的破坏。合理使用单例模式能提高系统的稳定性和资源利用率。