引言:引言:设计模式是我们项目中经常会涉及到的项目进行重构、解构时的一种方法,像常见的单例模式、工厂模式、策略模式、装饰器模式都是比较常用的,关于 23 种设计模式,大家可以找本书专门去翻看一下,在 Java 框架的源码中也不例外,设计模式的使用实在是太多了,本文就来分析 Spring 中用到的设计模式,本文承接上期文章。
题目
探秘 Spring 的设计模式-下
推荐解析
代理模式
优点
1)远程代理:通过代理对象,可以隐藏远程对象存在于不同地址空间的事实,使得客户端无需知道远程对象的存在细节,简化了客户端的调用过程。
2)虚拟代理:通过代理对象,可以延迟创建和初始化一个真实对象,直到客户端真正需要时才进行初始化,提高了系统的性能和效率。
3)安全代理:可以控制客户端对真实对象的访问权限,增强了系统的安全性。
4)智能指引:可以在代理对象中实现对真实对象的额外处理,例如对请求进行预处理、后处理等,增强了系统的功能。
缺点
1)增加复杂性:引入了代理对象,会增加系统的复杂性,使得代码量增加。
2)性能损失:在一定程度上会影响系统的性能,因为需要在代理对象和真实对象之间进行额外的调用。
使用场景
1)远程代理:当客户端需要访问远程对象时,可以使用代理模式,将访问请求通过代理对象发送给远程对象。
2)虚拟代理:当对象创建成本较高时,可以使用代理模式延迟对象的创建和初始化,直到真正需要时才进行创建。
3)安全代理:当需要控制客户端对真实对象的访问权限时,可以使用代理模式来实现安全代理。
4)智能指引:当需要在访问真实对象前进行一些额外操作时,例如对请求进行验证、记录日志等,可以使用代理模式来实现智能指引。
Spring 源码
JDK 动态代理:当目标对象实现了接口时,Spring 使用 JDK 动态代理来生成代理对象。JDK 动态代理是基于接口的,它通过在运行时创建一个接口的实现类来代理目标对象,并在代理对象的方法调用前后插入增强逻辑。
CGLIB 动态代理:当目标对象没有实现接口时,Spring 使用 CGLIB 动态代理来生成代理对象。CGLIB 动态代理通过继承目标对象生成代理对象的子类,并在子类中重写目标对象的方法来实现增强逻辑。
java
public interface UserService {
void addUser(String username);
}
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("Adding user: " + username);
}
}
创建切面类
java
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.UserService.addUser(..))")
public void beforeAddUser() {
System.out.println("Before adding user...");
}
}
模板方法模式
优点
1)代码复用:模板方法将算法的骨架定义在抽象类中,通过继承抽象类并实现基本方法,可以方便地复用代码。
2)扩展性:模板方法提供了一个稳定的算法骨架,允许子类根据需要实现或重写基本方法,从而扩展或修改算法的特定步骤,使得系统更加灵活。
3)封装变化:模板方法将不变的算法步骤封装在模板方法中,将可变的部分交给子类实现,从而封装了算法的变化,使得系统易于维护和扩展。
缺点
1)限制子类:模板方法将算法的骨架固定在抽象类中,可能会限制子类的灵活性,使得子类必须按照固定的算法执行,不能完全自由发挥。
2)复杂性:模板方法将算法分解为若干个基本方法,可能会增加系统的复杂性,降低了系统的可读性。
使用场景
1)框架设计:在框架设计中,通常使用模板方法定义算法的骨架,并留出一些抽象方法或钩子方法,允许子类根据需要定制具体的行为,从而实现框架的扩展性。
2)库函数设计:在库函数设计中,可以使用模板方法将常用的算法封装在模板方法中,提供给用户使用,并留出一些扩展点,允许用户根据需要自定义部分逻辑。
OJ 项目使用过模板方法,可以进行参考。
Spring 源码
java
public class JdbcTemplate implements JdbcOperations {
...
// 模板方法,定义了 JDBC 查询的执行流程
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(getDataSource());
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeQueries()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
else {
conToUse = createConnectionProxy(con);
}
return action.doInConnection(conToUse);
}
catch (SQLException ex) {
// ...
}
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
...
}
其他补充
鱼聪明 AI 的回答:
鱼聪明 AI 地址:https://www.yucongming.com/
观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。
下面是一个简单的观察者模式的实现示例:
Java
import java.util.ArrayList;
import java.util.List;
// 主题接口
interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题实现类
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
// 观察者接口
interface Observer {
void update();
}
// 具体观察者实现类
class ConcreteObserver implements Observer {
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject) {
this.subject = subject;
this.subject.addObserver(this);
}
@Override
public void update() {
System.out.println("Observer updated with state: " + subject.getState());
}
}
public class ObserverPatternExample {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver(subject);
ConcreteObserver observer2 = new ConcreteObserver(subject);
subject.setState(10);
subject.setState(20);
}
}
在上面的代码中,Subject
是主题接口,定义了添加观察者、移除观察者和通知观察者的方法。ConcreteSubject
是具体的主题实现类,维护了一个观察者列表,并在状态发生变化时通知所有观察者。
Observer
是观察者接口,定义了观察者的更新方法。ConcreteObserver
是具体的观察者实现类,当被观察者状态发生变化时,会调用观察者的更新方法进行相应的处理。
观察者模式的使用场景包括:
- 事件处理:当一个对象发生变化需要通知其他对象进行相应处理时,可以使用观察者模式。例如,GUI 应用中的按钮点击事件通知监听器进行处理。
- 发布-订阅系统:观察者模式可以用于实现发布-订阅系统,其中发布者是被观察者,订阅者是观察者。
- 模型-视图分离:在 MVC(Model-View-Controller)模式中,观察者模式常用于将模型和视图分离,当模型状态变化时,视图可以及时更新。
- 异步编程 :观察者模式可以用于实现异步编程中的回调机制,例如 Java 中的
CompletableFuture
类就是基于观察者模式设计的。
总的来说,观察者模式适用于对象之间存在一对多的依赖关系,当一个对象的状态发生变化时需要通知多个其他对象进行相应处理的场景。
欢迎交流
本文主要介绍代理模式和模版方法模式,其中代理模式的应用是比较广泛的,而且也比较容易上手,可以根据不同的业务场景选择设计模式,从而达到高内聚、低耦合的目的,在文末还有三个问题,欢迎小伙伴在评论区留言回答!
1)Spring框架中使用了哪些设计模式?请举例说明其在源码中的应用。
2)在 Spring 中,Bean的创建和管理是如何使用设计模式来实现的?
3)Spring中的依赖注入是如何利用设计模式来实现的?