Java常用设计模式大全
设计模式
什么是设计模式:
设计模式(Design Pattern)是软件开发中一套被反复使用、经过验证的代码设计经验总结,用于解决特定场景下的通用问题。它不是具体的代码实现,而是一种抽象的设计思想,描述了在特定情境下如何组织类、对象、接口之间的关系,以达到可复用、可扩展、可维护的代码目标。
设计模式的核心价值
- 复用性:解决同类问题时,无需重复设计,直接套用成熟方案。
- 可读性:遵循公认模式的代码,更容易被其他开发者理解(类似 “编程术语”)。
- 可扩展性:模式的结构设计通常预留了扩展点,便于后续功能迭代。
- 可靠性:经过大量实践验证,减少因设计缺陷导致的 bug。
常用的面向对象设计原则包括7个,这些原则并不是孤立存在的,它们相互依赖,相互补充。
- 开闭原则(Open Closed Principle,OCP)
- 单⼀职责原则(Single Responsibility Principle, SRP)
- 里氏替换原则(Liskov Substitution Principle,LSP)
- 依赖倒置原则(Dependency Inversion Principle,DIP)
- 接口隔离原则(Interface Segregation Principle,ISP)
- 合成/聚合复⽤原则(Composite/Aggregate Reuse Principle, C/ARP)
- 最少知识原则(Least Knowledge Principle,LKP)或者迪⽶特法则 (Law of Demeter,LOD)
1.创建者模式
创建者模式的主要关注点是:怎样创建对象,它的主要特点是将对象的创建与使用分离
这样可以降低系统的耦合度,使用者不需要关注对象的创建细节
创建者模式又称创建型模式,由五种模式构成
- 单例模式
- 工厂方法模式
- 抽象工厂模式
- 建造者模式
- 原型模式
工厂模式
说⼀说简单⼯⼚模式
简单工厂模式指由⼀个工厂对象来创建实例,客户端不需要关注创建逻 辑,只需提供传入工厂的参数。
如图所示:
适⽤于⼯⼚类负责创建对象较少的情况,缺点是如果要增加新产品,就需 要修改⼯⼚类的判断逻辑,违背开闭原则,且产品多的话会使⼯⼚类⽐较 复杂。
Spring中的BeanFactory使用简单的工厂模式,根据传入一个唯一的标识来获得Bean对象
工厂方法模式了解了吗
和简单工厂模式中工厂负责⽣产所有产品相比,工厂方法模式将生成具体 产品的任务分发给具体的产品工厂。
也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂,这样不用通过指定类型来创建对象了。
抽象工厂模式
简单工厂模式和工厂方法模式不管工厂怎么拆分抽象,都只针对一类产品,如果要生产另外一种产品。就很难解决
所以引用了抽象工厂模式
抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新产品的创建,当然前提是子工厂支持生产该产品,否则继承的这个接口可以什么也不干
从上⾯类图结构中可以清楚的看到如何在工厂方法模式中通过增加新产品 接口来实现产品的增加的。
单例模式
什么是单例模式,单例模式的特点是什么
单例模式属于创建型模式,⼀个单例类在任何情况下都只存在⼀个实例, 构造方法必须是私有的、由自己创建⼀个静态变量存储实例,对外提供⼀ 个静态公有方法获取实例
优点是内存中只有一个实例,减少了开销,尤其是频繁创建和销毁实例的情况下并且可以避免对资源的多重占用,缺点是没有抽象层,难以扩展,与单一职责原则冲突
单例模式主要有以下结构:
- 单例类,只能创建一个实例的类
- 访问类,使用单例类
单例模式的常见写法有哪些
饿汉式,线程安全
饿汉式单例模式,就是类一加载就创建对象,这种方式比较常用,但是容易产生垃圾对象,浪费内存空间。
public class Singleton {// 类加载时立即初始化实例(静态常量)private static final Singleton INSTANCE = new Singleton();// 私有构造函数,防止外部实例化private Singleton() {}// 公共访问点public static Singleton getInstance() {return INSTANCE;}
}
- 优点:线程安全,没有加锁,执行效率较高
- 缺点:不是懒加载,类加载时就初始化,浪费内存空间
懒加载(lazy loading):使用时再创建对象(懒汉式的方法)
饿汉式单例是如何保证线程安全的呢,它是基于类加载机制避免了多线程的同步问题,但是如果类被不同的类加载器加载就会创建不同实例。
类加载的原子性
Java 虚拟机(JVM)在加载类时,会保证类的初始化阶段是线程安全的。当多个线程同时请求加载同一个类时,JVM 会通过内部锁机制确保类的静态初始化代码(包括静态变量的赋值)只被执行一次,且对所有线程可见。静态常量的不可变性
INSTANCE
被声明为final
,确保其引用在初始化后不可变。一旦类加载完成,INSTANCE
的引用就被固定,所有线程看到的都是同一个实例。提前初始化
实例在类加载时就被创建,而不是在第一次调用getInstance()
时。因此,后续的调用只是返回已存在的实例,不存在多线程竞争创建实例的问题。
懒汉式,线程不安全
这种方式在单线程下使用没有问题,对于多线程是无法保证单例的,这里列出来是为了和后面使用锁保证线程安全做对比。
- 优点:懒加载
- 缺点:线程不安全
懒汉式单例在第一次调用 getInstance()
时才创建实例,典型实现如下:
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) { // 多线程可能同时进入此条件instance = new LazySingleton(); // 非原子操作,存在竞态条件}return instance;}
}
当多个线程同时调用 getInstance()
时,可能会出现:
- 线程 A 判断
instance == null
后,尚未创建实例; - 线程 B 同时判断
instance == null
,也进入创建逻辑; - 最终导致多个实例被创建。
如何保证懒汉式线程安全
懒汉式单例如何保证线程安全呢?通过 synchronized 关键字加锁保证线程 安全, synchronized 可以添加在方法上面,也可以添加在代码块上面,这里演示添加在方法上面,存在的问题是 每⼀次调用 getInstance 获取实例时 都需要加锁和释放锁,这样是非常影响性能的
- 优点:懒加载,线程安全
- 缺点:效率较低
public class Singleton {// 1、私有化构造⽅法
private Singleton(){ }// 2、定义⼀个静态变量指向⾃⼰类型
private static Singleton instance;// 3、对外提供⼀个公共的⽅法获取实例}public synchronized static Singleton getInstance() {if (instance == null) {instance = new Singleton();return instance;}}
静态内部类
public class Singleton {// 1、私有化构造⽅法
private Singleton() {}// 2、对外提供获取实例的公共⽅法
public static Singleton getInstance() {return InnerClass.INSTANCE;}// 定义静态内部类
private static class InnerClass{private final static Singleton INSTANCE = new
Singleton();}}
优点:懒加载,线程安全,效率较高,实现简单
枚举单例
public enum Singleton {INSTANCE;public void doSomething(String str) {System.out.println(str);}}
优点:简单,高效,线程安全,可以避免通过反射破坏枚举单例
枚举在 java 中与普通类⼀样,都能拥有字段与方法,而且枚举实例创建是 线程安全的,在任何情况下,它都是⼀个单例,可以直接通过如下方式调用获取实例:
Singleton singleton = Singleton.INSTANCE;
适配器模式
什么是适配器模式
在我们的应⽤程序中我们可能需要将两个不同接口的类来进⾏通信,在不 修改这两个的前提下我们可能会需要某个中间件来完成这个衔接的过程。 这个中间件就是适配器。所谓适配器模式就是将⼀个类的接口,转换成客 户期望的另⼀个接口。它可以让原本两个不兼容的接口能够无缝完成对接
作为中间件的适配器将目标类和适配者解耦,增加了类的透明性和可复用性。
类适配器
原理:通过类继承实现适配,继承Target的接口,继承Adaptee的实现
对象适配器
原理:通过类对象组合实现适配
- Target:定义Client真正使用的接口
- Adaptee:其中定义了一个以及存在的接口,也是我们需要进行适配的接口
- Adapter:对Adaptee 和 Target的接口进行适配,保证对Target中接口的调用可以间接地转换为对Adaptee中接口的调用。
适配器模式的优缺点
优点:
- 提高了类的复用;
- 组合若干关联对象形成对外提供统一服务的接口;
- 扩展性,灵活性好
缺点:
- 过多使用适配模式容易造成代码功能和逻辑意义混淆
- 部分语言对继承的限制,可能至多只能适配一个适配者类,而且目标类型必须是抽象类
2.结构型模式
结构型模式通过类和接口间的继承和引⽤实现创建复杂结构的对象。包括适配器/桥接模式/过滤器/组合/装饰器/外观/享元/代理模式。
结构型模式由下面几种模式构成
- 适配器模式
- 桥接模式
- 组合模式
- 装饰模式
- 外观模式
- 享元模式
- 代理模式
代理模式
什么是代理模式
代理模式的本质是一个中间件,主要目的是解耦服务提供者和使用者,使用者通过代理间接地访问服务提供者,便于后者的封装和控制。是一种结构性模式。
- Subject: 定义 RealSubject 对外的接口,且这些接⼝必须被 Proxy 实现, 这样外部调用proxy 的接口最终都被转化为对 realsubject 的调用。
- RealSubject: 真正的目标对象。
- Proxy: 目标对象的代理,负责控制和管理目标对象,并间接地传递外部对目标对象的访问。
- Remote Proxy: 对本地的请求以及参数进行序列化,向远程对象发送请 求,并对响应结果进行反序列化,将最终结果反馈给调用者;
- Virtual Proxy: 当目标对象的创建开销比较大的时候,可以使用延迟或者 异步的⽅式创建目标对象;
- Protection Proxy: 细化对目标对象访问权限的控制;
静态代理和动态代理的区别
1. 灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建⼀个代理类。另外,静态 代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这 是非常麻烦的!
2. JVM 层⾯ :静态代理在编译时就将接口、实现类、代理类这些都变成 了⼀个个实际的 class文件。而动态代理是在运行时动态⽣成类字节码,并加载到 JVM 中的。
装饰器模式
什么是装饰器模式
装饰器模式主要对现有的类对象进行包裹和封装,以期望在不改变类对象及其类定义的情况下,为对象添加额外功能。是一种对象结构型模式。需要注意的是,该过程是通过调用被包裹之后的对象完成功能添加的,而不是直接修改现有对象的行为,相当于增加了中间层
- Component: 对象的接⼝类,定义装饰对象和被装饰对象的共同接口;
- ConcreteComponent: 被装饰对象的类定义;
- Decorator: 装饰对象的抽象类,持有⼀个具体的被修饰对象,并实现接口类继承的公共接口;
- ConcreteDecorator: 具体的装饰器,负责往被装饰对象添加额外的功能;
装饰器模式的应用场景
如果希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为,可以使用装饰模式
装饰能将业务逻辑组织为层次结构, 你可为各层创建⼀个装饰, 在运行时 将各种不同逻辑组合成对象。 由于这些对象都遵循通⽤接⼝, 客户端代码 能以相同的方式使用这些对象
如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。
许多编程语言使用final 最终关键字来限制对某个类的进一步扩展。 复用最终类已有行为的唯一方法是使用装饰模式: 用封装器对其进行封装。
装饰器模式将核心逻辑与扩展逻辑分离,核心类只关注自身职责,装饰器专注于扩展,符合 “单一职责原则”
Java IO 流是装饰器模式的经典应用:
- 核心类:
InputStream
(字节输入流)、FileInputStream
(读取文件的核心功能)。 - 装饰器:
BufferedInputStream
(添加缓冲功能,提高读取效率)、DataInputStream
(添加读取基本数据类型的功能)。
核心流与装饰器分离,用户可根据需求组合(如new DataInputStream(new BufferedInputStream(new FileInputStream("file.txt")))
),既清晰又灵活。
其典型应用除了 Java IO,还有 Spring 中的 BeanWrapper
、Servlet 中的 Filter
等,都是通过装饰器模式实现功能的动态增强。
3.行为模式
行为模式由以下几种模式构成
- 访问者模式
- 模板模式
- 策略模式
- 状态模式
- 观察者模式
- 备忘录模式
- 中介者模式
- 迭代器模式
- 解释器模式
- 命令模式
- 责任链模式
观察者模式
观察者模式是什么
观察者模式主要用于处理对象间的一对多关系,是一种对象行为模式,该模式的实际应用场景比较容易确认,当一个对象状态发生变化时,所有该对象的关注者均能收到状态变化通知,以进行相应的处理
Subject: 抽象被观察者,仅提供注册和删除观察者对象的接口声明。
ConcreteSubject: 具体被观察者对象,该对象中收集了所有需要被通知的 观察者,并可以动态的增删集合中的观察者。当其状态发生变化时会通知所有观察者对象。
Observer: 抽象观察者,为所有观察者定义获得通知的统⼀接口;
ConcreteObserver: 观察者对象,其关注对象为 Subject,能接受 Subject 变化时发出的通知并更新⾃身状态。
观察者模式的优缺点
优点:
- 被观察者和观察者之间是抽象耦合的
- 耦合度较低,两者之间的关联仅仅在于消息的通知
- 被观察者无需关心他的观察者
- 支持广播通信
缺点:
- 观察者只知道被观察对象发生了变化,但不知道变化的过程和缘由
- 观察者同时也可能是被观察者,消息传递的链路可能会过长,完成所有通知花费时间比较多
- 如果观察者和被观察者之间产生循环依赖,或者消息传递链路形成闭环,会导致无限循环.
一般项目是怎么用观察者模式的
在支付场景下,用户购买⼀件商品,当支付成功之后三⽅会回调自身,在 这个时候系统可能会有很多需要执行的逻辑(如:更新订单状态,发送邮 件通知,赠送礼品…),这些逻辑之间并没有强耦合,因此天然适合使⽤ 观察者模式去实现这些功能,当有更多的操作时,只需要添加新的观察者就能实现,完美实现了对修改关闭,对扩展开放的开闭原则。
责任链模式
什么是责任链模式
⼀个请求沿着⼀条“链”传递,直到该“链”上的某个处理者处理它为止
⼀个请求可以被多个处理者处理或处理者未明确指定时。 责任链模式非常简单异常好理解,相信我它比单例模式还简单易懂,其应用也几乎无所不在,甚至可以这么说,从你敲代码的第⼀天起你就不知不觉用过了它最原始的裸体结构: switch-case 语句。
责任链模式的应用场景
- 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预 先未知时, 可以使用责任链模式。该模式能将多个处理者连接成⼀条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
- 当必须按顺序执行多个处理者时, 可以使用该模式。无论你以何种顺 序将处理者连接成⼀条链, 所有请求都会严格按照顺序通过链上的处理者。
策略模式
什么是策略模式
策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对⼀组算法,将每⼀个算法封装到具有共同接口的独立的类中,从而使得它们可以 相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。 其主要目的是通过定义相似的算法,替换 if else 语句写法,并且可以随时相互替换。
策略模式有什么好处
定义了一系列封装好了算法,行为的对象,它们可以相互替换
举例: Java.util.List 就是定义了⼀个增( (set)、查( add )、删( remove )、改 indexOf )策略,至于实现这个策略的 ArrayList 、 LinkedList 等类,只是在具体实现时采用了不同的算法。但因为它们策略⼀样,不考虑速度的情况下,使⽤时完全可以互相替换使用。
Spring使用了哪些设计模式
1. 单例模式(Singleton Pattern)
- 应用场景:Spring 的 Bean 默认作用域是
singleton
,确保每个 Bean 在容器中只有一个实例。 - 实现方式:Spring 通过容器管理 Bean 的生命周期,在首次请求时创建实例,后续请求直接返回该实例。
@Service // 默认单例
public class UserService {// ...
}
2. 工厂模式(Factory Pattern)
- 应用场景:Spring 的
BeanFactory
和ApplicationContext
作为工厂,负责创建和管理 Bean。 - 实现方式:通过配置(XML、注解、Java Config)定义 Bean 的创建方式,工厂根据配置生成实例。
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class); // 工厂创建 Bean
3. 代理模式(Proxy Pattern)
- 应用场景:Spring AOP(面向切面编程)通过动态代理实现,包括 JDK 动态代理(接口代理)和 CGLIB 代理(类代理)。
- 实现方式:在目标对象周围创建代理,拦截方法调用并织入切面逻辑(如日志、事务)。
@Service
public class UserService {@Transactional // 事务切面通过代理织入public void saveUser(User user) {// ...}
}
4. 装饰器模式(Decorator Pattern)
- 应用场景:Spring 的
BeanWrapper
类用于包装 Bean 实例,动态添加属性访问、类型转换等功能。 - 实现方式:通过包装原始 Bean,增强其功能而不改变原有结构。
BeanWrapper wrapper = new BeanWrapperImpl(new User());
wrapper.setPropertyValue("name", "John"); // 装饰器增强属性设置功能
5.观察者模式(Observer Pattern)
- 应用场景:Spring 的事件发布 - 订阅机制(
ApplicationEvent
和ApplicationListener
)。 - 实现方式:事件源(如
ApplicationContext
)发布事件,多个监听器异步监听并响应。
// 自定义事件
public class UserRegisterEvent extends ApplicationEvent {public UserRegisterEvent(Object source) {super(source);}
}
// 监听器
@Component
public class UserRegisterListener implements ApplicationListener<UserRegisterEvent> {@Overridepublic void onApplicationEvent(UserRegisterEvent event) {// 处理事件}
}
// 发布事件
applicationContext.publishEvent(new UserRegisterEvent(user));
6.策略模式(Strategy Pattern)
- 应用场景:Spring 的
ResourceLoader
根据不同资源类型(如 classpath、file、URL)选择不同加载策略。 - 实现方式:定义接口
ResourceLoader
,多种实现类(如ClassPathResourceLoader
、FileSystemResourceLoader
)代表不同策略。
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:config.properties"); // 动态选择策略
7.模板方法模式(Template Method Pattern)
- 应用场景:Spring 的 JdbcTemplate、RestTemplate 等模板类封装通用操作流程,将具体步骤延迟到子类实现。
- 实现方式:基类定义算法骨架,子类实现特定步骤(如 SQL 查询、响应处理)。
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List<User> users = jdbcTemplate.query("SELECT * FROM users", (rs, rowNum) -> {// 结果集映射(具体步骤)return new User(rs.getString("name"));
});
8.责任链模式(Chain of Responsibility Pattern)
- 应用场景:Spring MVC 的
HandlerInterceptor
链、Servlet 的Filter
链。 - 实现方式:多个拦截器 / 过滤器依次处理请求,形成链条,每个处理器可决定是否继续传递。
public class AuthInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 身份验证逻辑,返回 true 继续执行后续拦截器return true;}
}
9.适配器模式(Adapter Pattern)
- 应用场景:Spring MVC 的
HandlerAdapter
将不同类型的处理器(如 Controller、HttpRequestHandler)适配为统一接口。 - 实现方式:为每种处理器类型创建适配器,封装其调用逻辑。
public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler);
}
10.建造者模式(Builder Pattern)
- 应用场景:Spring 的
BeanDefinitionBuilder
用于构建复杂的 Bean 定义。 - 实现方式:通过链式调用设置 Bean 属性,最终构建完整的 BeanDefinition。
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
builder.addPropertyValue("userDao", userDao);
BeanDefinition definition = builder.getBeanDefinition();
Spring 框架通过设计模式实现了高内聚、低耦合的架构,其中:
- 单例、工厂、代理 是最核心的模式,支撑 Bean 管理和 AOP 功能;
- 观察者、责任链 用于事件处理和请求拦截;
- 模板方法、策略、适配器 简化数据访问和 MVC 流程。