Java设计模式的常见应用场景

本文介绍了Java I/O中的适配器模式与装饰器模式、Javac中的访问者模式、Tomcat中的门面模式、观察者模式、命令设计模式与责任链模式,以及Spring中的简单工厂模式、工厂方法模式、单例模式、代理模式、模板方法模式和策略模式。通过这些设计模式的讲解,读者可以更好地理解这些框架和技术的内部工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Java I/O中的设计模式

1、适配器模式

适配器模式就是把一个类的接口变换成客户端所能接受的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作。通常被用在一个项目需要引用一些开源框架来一起工作时,这些框架的内部都有一些关于环境信息的接口,需要从外部引入,但是外部的接口不一定能匹配,在这种情况下,就需要适配器模式来转换接口。
这里写图片描述
Java的I/O类库中有许多这样的需求,如将字符串转成字节数据保存到文件中,将字节数据变成数据流等。具体来说,InputStreamReader和OutputStreamWriter就是适配器的体现。InputStreamReader实现了Reader接口,并且持有InputStream的引用,其作用是将InputStream适配到Reader。源角色就是InputStream代表的实例对象,目标角色就是Reader类。OutputStreamWriter也是类似的方式。

2、装饰器模式

装饰器的作用是使得被装饰者功能更强大,而且装饰前后的使用方式不变。Java I/O类库中有许多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的。以FileInputStream为例,其类结构如下:
这里写图片描述
由于java I/O库需要很多性能的各种组合,如果这些性能都是用继承来实现,那么每一种组合都需要一个类,这样就会造成大量行重复的类出现。如果采用装饰模式,那么类的数目就会大大减少,性能的重复也可以减至最少。因此装饰模式是java I/O库基本模式。装饰模式的引进,造成灵活性和复杂性的提高。因此在使用 java I/O 库时,必须理解java I/O库是由一些基本的原始流处理器和围绕它们的装饰流处理器所组成的。
InputStream类是以抽象组件的形式存在,而FileInputStream就是具体组件,它实现了抽象接口的所有方法,并且持有InputStream对象的引用。FileInputStream就是一个装饰类,而BufferInputStream是这个装饰类的具体实现者,它给InputStream加入了新的功能,使得InputStream读取的数据保存在内存中,从而提高读取性能。

3、适配模式和装饰模式的区别

适配模式是为了处理两个借口不一致,改变现有接口使其匹配。
装饰模式是在不改变现有接口的前提下,加入新的功能。

二、Javac中的访问者模式

javac 是java语言编程编译器。全称javacompilation。javac工具读由java语言编写的类和接口的定义,并将它们编译成字节代码的class文件。javac 可以隐式编译一些没有在命令行中提及的源文件。用 -verbose 选项可跟踪自动编译。当编译源文件时,编译器常常需要它还没有识别出的类型的有关信息。对于源文件中使用、扩展或实现的每个类或接口,编译器都需要其类型信息。这包括在源文件中没有明确提及、但通过继承提供信息的类和接口。
Javac的编译过程涉及许多语法分析,所有就有语法分析器、语义分析器和代码生成器,期间需要多次遍历语法树。然而每次遍历语法树都会进行不同的处理动作,这是如何实现的呢?就是通过采用访问者模式设计的,每次遍历都是一次访问者的执行过程。
访问者模式可以使数据结构和对数据结构的操作解耦,使得增加对数据结构的操作不需要去修改数据结构,也不必去修改原有的操作,从而执行时再定义新的Visitor实现者就行了。在Javac中不同的编译阶段都定义了不同的访问者模式实现。

三、Tomcat中的设计模式

1、门面模式

Tomcat中门面设计模式使用得很多,因为Tomcat中有很多组件,每个组件要相互交互数据,用门面设计模式隔离数据是个很好的方法。
这里写图片描述
可以看到,HttpRequestFacade类封装了HttpRequest接口,能够提供数据,通过HttpRequestFacade访问到的数据被代理到HttpReauest中、通常被封装的对象都被设为Private或者Protectd的,防止在Facade中直接访问。

2、观察者模式

Tomcat中观察者模式也有多处使用,前面讲的控制组件生命周期的Lifecycle就是这 种模式的体现,还有对Servlet实例的创建、Session的管理、Container等都是同样的原理。 下面主要看一下Lifecycle的具体实现。
Lifecycle的观察者模式结构图如图所示。
这里写图片描述
在上面的结构图中,LifecycleListener代表的是抽象观察者,它定义一个lifecycleEvent 方法,这个方法就是当主题变化时要执行的方法。ServerLifecycleListener代表的是具体的 观察者,它实现了 LifecycleListener接口的方法,就是这个具体的观察者具体的实现方式。 Lifecycle接口代表的是抽象主题,它定义了管理观察者的方法和它所要做的其他方法。而 StandardServer代表的是具体主题,它实现了抽象主题的所有方法。这里Tomcat对观察者 做了扩展,谓加了另外两个类:LifecycleSupport和LifecycleEvent,它们作为辅助类扩展 了观察者的功能。LifecycleEvent使得可以定义事件类别,不同的事件可区别处理,更加灵活。LifecycleSupport类代理了主题对多观察者的管理,将这个管理抽出来统一实现,以 后如采修改只要修改LifecycleSupport类就可以了,不需要去修改所有的具体主题,因为 所有具体主题对观察者的操作都被代理给LifecycleSupport类了。这可以认为是观察者模式的改进版。

3、命令设计模式

Tomcat中命令模式在Connector和Container组件之间有体现,Tomcat作为一个应用 服务器,无疑会接收到很多请求,如何分配和执行这些请求是必须的功能。
下面分析一下Tomcat是如何实现命令模式的,下图是Tomcat命令模式的结构图。
这里写图片描述
Connector作为抽象请求者,HttpConnector作为具体请求者。HttpProcessor作为命令。 Container作为命令的抽象接受者,ContainerBase作为具体的接受者。客户端就是应用服务器Server组件了。Server首先创建命令请求者HttpConnector对象,然后创建命令 HttpProcessor对象。再把命令对象交给命令接受者ContainerBase容器来处理,命令最终是被Tomcat的Container执行的。命令可以以队列的方式进来,Container也可以以不同的 方式来处理请求,如HTTP1.0协议和HTTP1.1的处理方式就不同。

4、责任链模式

Tomcat 中一个最容易发现的设计模式就是责任链设计模式,这个设计模式也是 Tomcat 中 Containe设计的基础,整个容器就是通过一个链连接在一起的,这个链一直将请求正确地传递给最终处理请求的那个 Servlet 。在Tomcat中这种设计模式儿乎被完整地使用,Tomcat的容器设置就是责任链模式,从Engine到Host再到Cortex,一直到Wrapper都通过这个链传递请求。
这里写图片描述

四、Spring中的设计模式

1、简单工厂模式

又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。
spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。如下配置,就是在 HelloItxxz 类中创建一个 itxxzBean。

<beans>
    <bean id="singletonBean" class="com.kang.HelloItxxz">
        <constructor-arg>
            <value>Hello! 这是singletonBean!value>
        </constructor-arg>
   </ bean>

    <bean id="itxxzBean" class="com.kang.HelloItxxz"
        singleton="false">
        <constructor-arg>
            <value>Hello! 这是itxxzBean! value>
        </constructor-arg>
    </bean>

</beans>

2、工厂方法模式

通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。
以工厂方法中的静态方法为例讲解一下:

import java.util.Random;
public class StaticFactoryBean {
      public static Integer createRandom() {
           return new Integer(new Random().nextInt());
       }
}

建一个config.xm配置文件,将其纳入Spring容器来管理,需要通过factory-method指定静态方法名称,createRandom方法必须是static的,才能找到

<bean id="random"
class="example.chapter3.StaticFactoryBean" factory-method="createRandom" scope="prototype"
/>

3、单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。 Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定

4、代理模式

在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。

5、模板方法模式

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
Template Method模式一般是需要继承的。这里想要探讨另一种对Template Method的理解。spring中的JdbcTemplate,在用这个类时并不想去继承这个类,因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。这可能是Template Method不需要继承的另一种实现方式吧。

6、策略模式

Spring中的策略模式使用多如牛毛,所谓策略模式就是定义了算法族,分别封装起来,让他们之前可以互相转换,此模式然该算法的变化独立于使用算法的客户。Spring的事务管理机制就是典型的策略模式,Spring事务策略是通过PlatformTransactionManager接口实现的,它是整个Spring事务的核心。它是对事务策略的一个高度抽象,不依赖于任何具体的事务策略,而对于底层的具体的事务策略它相应的有不同的实现类。而对于不同的事务策略的切换通常由Spring容器来负责管理,应用程序既无须与具体的事务API耦合,也无须与特定的实现类耦合而将应用和持久化技术,事务API彻底分离开来。

五、SpringMVC中的模板模式

所谓模板模式就是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。SpringMVC在保证整个框架流程稳定的情况下,预留很多口子,而这些口子都是所谓的模板方法,可以自由指定,从而保证了灵活性,接下来的很多使用最佳实践都是基于这种设计模式才可以实现。例如,下面的代码中doResolveException(..)就是一个口子,子类方法doResolveException(..)可以定义具体如何处理异常。

public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
        Exception ex) {
    if (shouldApplyTo(request, handler)) {
        logException(ex, request);
        prepareResponse(ex, response);
        return doResolveException(request, response, handler, ex);
    } else {
        return null;
    }
}

protected abstract ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
        Object handler, Exception ex);
<think>好的,我现在需要回答用户关于Java常见设计模式及其应用场景的问题。首先,我需要回顾一下设计模式的基本概念,然后整理出Java中常用的几种设计模式,并分别说明它们的定义、结构适用场景。 用户之前已经询问过MyBatis的动态SQL标签,现在转向设计模式,可能是在学习Java的高级主题,或者准备面试。因此,回答需要结构清晰,内容准确,同时结合实际应用场景,帮助用户理解何时使用这些模式。 首先,设计模式通常分为创建型、结构型行为型三类。我需要从每个类别中挑选几个最常用的模式。创建型可能包括单例、工厂、建造者;结构型如适配器、代理、装饰器;行为型如观察者、策略、责任链等。 接下来,每个模式的介绍需要包括:定义、核心角色(如果有)、典型应用场景,以及可能的Java SDK或框架中的例子。例如,单例模式用于全局唯一实例,工厂模式解耦对象的创建,适配器模式解决接口不兼容问题等。 需要注意避免过于技术化的描述,保持简洁易懂。同时,要确保每个模式的应用场景具体,让用户能够联想到实际开发中的情况。例如,Spring框架中的Bean默认是单例,Java中的Collections.sort()使用策略模式等。 另外,用户可能对某些模式的实现细节感兴趣,比如单例模式的双重检查锁定,工厂方法模式与抽象工厂的区别,但根据问题,重点应放在应用场景而非具体代码实现。不过,适当给出简单的代码示例有助于理解。 需要检查是否有遗漏的重要模式,比如代理模式在Spring AOP中的应用,或者观察者模式在事件驱动系统中的作用。确保覆盖常见的模式,但不需要列举所有23种,而是选择最常用的大约10个左右。 最后,总结部分可以强调设计模式解决特定问题的优点,以及过度使用可能带来的复杂性。提醒用户根据实际需求选择合适的模式,而不是为了使用模式而模式。 现在组织内容,分点介绍每个模式,保持段落简短,结构清晰,使用标题子标题帮助阅读。可能使用数字列表,每个模式一个条目,包含定义、结构、应用场景例子。 需要确保术语准确,比如“抽象工厂”与“工厂方法”的区别,避免混淆。同时,检查是否有拼写错误或概念错误,比如单例模式的线程安全问题,不同实现方式的优缺点。 可能还需要考虑用户的后续问题,比如如何选择合适的设计模式,或者某些模式之间的对比,但在当前回答中先专注于介绍常见的模式应用场景。 完成草稿后,通读一遍,确保逻辑连贯,例子恰当,语言通俗易懂,符合中文表达习惯,没有使用Markdown格式,符合用户要求的格式。</think>以下是 Java常见设计模式及其应用场景的清晰总结,帮助开发者理解何时使用这些模式解决实际问题: --- ### 一、创建型模式(关注对象创建) 1. **单例模式 (Singleton)** **定义**:确保一个类只有一个实例,并提供全局访问点。 **应用场景**: - 需要全局唯一资源时,如数据库连接池、日志管理器。 - 工具类避免重复创建对象。 **Java 示例**: ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 2. **工厂方法模式 (Factory Method)** **定义**:定义一个创建对象的接口,由子类决定实例化哪个类。 **应用场景**: - 需要解耦对象创建逻辑(如数据库驱动切换)。 - Spring 的 `BeanFactory` 通过配置生成对象。 **示例**: ```java public interface Car { void drive(); } public class Tesla implements Car { /* ... */ } public class CarFactory { public Car createCar(String type) { if ("tesla".equals(type)) return new Tesla(); else throw new IllegalArgumentException(); } } ``` 3. **抽象工厂模式 (Abstract Factory)** **定义**:提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。 **应用场景**: - 需要创建一组关联对象(如跨平台 UI 组件:按钮 + 文本框)。 **Java 示例**: Java 的 `javax.xml.parsers.DocumentBuilderFactory` 根据配置生成 XML 解析器。 4. **建造者模式 (Builder)** **定义**:分步骤构建复杂对象,允许灵活配置。 **应用场景**: - 构造参数多且可选(如 `StringBuilder`、Lombok 的 `@Builder`)。 - 链式调用提升可读性。 **示例**: ```java User user = new UserBuilder().name("Alice").age(30).build(); ``` --- ### 二、结构型模式(关注对象组合) 5. **适配器模式 (Adapter)** **定义**:将一个类的接口转换为另一个接口,使不兼容的类可以协作。 **应用场景**: - 旧系统接口改造(如 JDBC 驱动适配不同数据库)。 **Java 示例**: `Arrays.asList()` 将数组适配为 `List` 接口。 6. **代理模式 (Proxy)** **定义**:为其他对象提供一种代理以控制对这个对象的访问。 **应用场景**: - 延迟加载(MyBatis 的 Mapper 代理)。 - AOP 实现日志、权限控制(Spring 动态代理)。 **示例**: ```java public interface Image { void display(); } public class ProxyImage implements Image { private RealImage realImage; public void display() { if (realImage == null) realImage = new RealImage(); realImage.display(); // 延迟加载实际图片 } } ``` 7. **装饰器模式 (Decorator)** **定义**:动态地为对象添加额外职责,比继承更灵活。 **应用场景**: - Java IO 流(如 `BufferedReader` 包装 `FileReader`)。 **示例**: ```java InputStream is = new BufferedInputStream(new FileInputStream("test.txt")); ``` --- ### 三、行为型模式(关注对象交互) 8. **观察者模式 (Observer)** **定义**:定义对象间的一对多依赖,当一个对象状态改变时,所有依赖者自动收到通知。 **应用场景**: - 事件驱动系统(如 GUI 按钮点击事件)。 **Java 示例**: Java 内置的 `java.util.Observable` `Observer` 接口(已过时,但概念广泛用于消息队列)。 9. **策略模式 (Strategy)** **定义**:定义一系列算法,使其可以相互替换,且算法的变化独立于客户端。 **应用场景**: - 支付方式切换(支付宝、微信支付)。 - `Collections.sort()` 通过 `Comparator` 指定排序策略。 **示例**: ```java public interface PaymentStrategy { void pay(int amount); } public class Alipay implements PaymentStrategy { /* ... */ } public class PaymentContext { private PaymentStrategy strategy; public void executePayment(int amount) { strategy.pay(amount); } } ``` 10. **责任链模式 (Chain of Responsibility)** **定义**:将请求的发送者接收者解耦,使多个对象都有机会处理请求。 **应用场景**: - 审批流程(如报销审批:经理→总监→CEO)。 - Servlet 过滤器链(`FilterChain`)。 --- ### 四、其他常用模式 11. **模板方法模式 (Template Method)** **定义**:定义一个算法骨架,将某些步骤延迟到子类实现。 **应用场景**: - 框架中固定流程(如 Spring 的 `JdbcTemplate` 执行 SQL 步骤固定,但 SQL 可变)。 12. **门面模式 (Facade)** **定义**:为复杂子系统提供一个统一的高层接口。 **应用场景**: - 简化 API 调用(如 SLF4J 封装不同日志框架)。 --- ### **总结:何时使用设计模式?** - **代码复用**:通过模式避免重复代码(如工厂解耦对象创建)。 - **扩展性**:预留扩展点(如策略模式支持新增算法)。 - **可维护性**:通过松耦合提升代码可读性(如观察者模式分离事件源监听者)。 - **避免过度设计**:优先遵循 KISS(Keep It Simple)原则,在复杂度上升时再引入模式。 合理使用设计模式能提升代码质量,但需结合具体场景,避免为模式而模式!
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值