Spring Boot 经典九设计模式全览
在Spring Boot中,设计模式的应用广泛且重要,它们有助于提高代码的可维护性、可扩展性和复用性。以下是Spring Boot中经典的9种设计模式及其代码案例:
1. 单例模式(Singleton Pattern)
在Spring中,bean默认就是单例模式。Spring通过单例注册表的方式来实现单例,即维护一个Map来存储单例类的实例。
// 单例模式示例
public class SingletonService {
private static SingletonService instance;
private SingletonService() {}
public static SingletonService getInstance() {
if (instance == null) {
instance = new SingletonService();
}
return instance;
}
}
2. 工厂模式(Factory Pattern)
工厂模式用于创建对象,而无需指定创建对象的具体类。Spring Boot中可以通过@Bean注解在配置类中实现工厂方法。
1. 定义接口或抽象类
// 用户接口
public interface ReturnUser {
List<String> getUserByType();
}
2. 实现接口或继承抽象类
然后,创建实现该接口或继承该抽象类的具体类。
// 机构用户实现类
@Component
public class OrgUserImpl implements ReturnUser {
@Override
public List<String> getUserByType() {
// 业务逻辑
return Arrays.asList("org1", "org2", "org3");
}
}
// 角色用户实现类
@Component
public class RoleUserImpl implements ReturnUser {
@Override
public List<String> getUserByType() {
// 业务逻辑
return Arrays.asList("role1", "role2", "role3");
}
}
3. 创建工厂类
接下来,创建一个工厂类,用于生成具体类的实例。
// 用户工厂类
@Component
public class ReturnUserFactory {
@Autowired
private OrgUserImpl orgUser;
@Autowired
private RoleUserImpl roleUser;
public ReturnUser getUserList(String module) {
switch (module) {
case "org":
return orgUser;
case "role":
return roleUser;
default:
return null;
}
}
}
4. 在Spring Boot中使用工厂类
你可以在你的Spring Boot应用程序中的任何地方使用工厂类来创建对象。例如,在一个控制器中:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ReturnUserController {
@GetMapping("/returnUser")
public String getAnimalSound(@RequestParam String type) {
ReturnUser returnUser = AnimalFactory.getUserList(type);
if (returnUser != null) {
returnUser.makeSound();
return "The returnUser makes the sound: " + returnUser.makeSound();
} else {
return "Unknown returnUser type";
}
}
}
3. 代理模式(Proxy Pattern)
1. 定义接口
首先,定义一个接口,这是被代理对象必须实现的。
public interface Service {
void performTask();
}
2. 实现接口
然后,创建一个实现该接口的具体类。
public class RealService implements Service {
@Override
public void performTask() {
System.out.println("Performing real service task.");
}
}
3. 创建代理类
接下来,创建一个代理类,它实现了相同的接口,并在调用实际对象的方法之前或之后添加额外的行为。
public class ServiceProxy implements Service {
private final Service realService;
public ServiceProxy(Service realService) {
this.realService = realService;
}
@Override
public void performTask() {
System.out.println("Performing proxy task before real service.");
realService.performTask();
System.out.println("Performing proxy task after real service.");
}
}
4. 在Spring Boot中使用代理
你可以在你的Spring Boot应用程序中的任何地方使用代理类。例如,在一个控制器中:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServiceController {
private final Service service;
// 你可以通过构造函数注入来传递代理对象,或者你可以直接在控制器中创建代理对象
public ServiceController(Service realService) {
this.service = new ServiceProxy(realService);
}
@GetMapping("/service")
public String getService() {
service.performTask();
return "Service task performed with proxy.";
}
}
但是,请注意,在上面的例子中,我们并没有真正利用Spring的依赖注入来管理代理的创建。在实际应用中,你可能会希望Spring来管理这些代理对象。这可以通过使用Spring AOP(面向切面编程)来实现,它允许你在不修改源代码的情况下向现有对象添加行为。
代理模式为其他对象提供一种代理以控制对这个对象的访问。Spring AOP(面向切面编程)就是代理模式的一个应用。
// 切面类
@Aspect
@Component
public class MyAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return proceed;
}
}
4. 观察者模式(Observer Pattern)
在Spring Boot中使用观察者模式(Observer Pattern)可以让你构建一个能够自动通知和更新依赖对象(观察者)的系统,当某个对象(主题)的状态发生变化时。Spring Boot中的事件监听机制就是观察者模式的一个应用。
1. 定义主题接口
首先,你需要定义一个主题接口,它包含添加、移除和通知观察者的方法。
// Subject.java
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
2. 实现具体的主题
接下来,实现一个具体的主题类,该类将维护一个观察者列表,并在状态变化时通知它们。
// ConcreteSubject.java
import java.util.ArrayList;
import java.util.List;
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
public void setState(String state) {
this.state = state;
notifyObservers();
}
public String getState() {
return state;
}
}
3. 定义观察者接口
然后,定义一个观察者接口,它包含一个更新方法,当主题状态变化时被调用。
// Observer.java
public interface Observer {
void update(Subject subject);
}
4. 实现具体的观察者
实现具体的观察者类,这些类将响应主题的状态变化。
// ConcreteObserver.java
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(Subject subject) {
ConcreteSubject concreteSubject = (ConcreteSubject) subject;
System.out.println(name + " received state update: " + concreteSubject.getState());
}
}
5. 在Spring Boot应用中使用
最后,在Spring Boot应用中使用这些类。你可以通过配置类或直接在控制器、服务等组件中实例化它们。
// ObserverPatternApplication.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ObserverPatternApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ObserverPatternApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
ConcreteSubject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setState("New State");
}
}
在这个示例中,ObserverPatternApplication
是我们的Spring Boot应用主类。它创建了一个ConcreteSubject
对象,并注册了两个ConcreteObserver
对象。然后,它更改主题的状态,这将触发对观察者的通知。
5. 策略模式(Strategy Pattern)
策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以互换。Spring Boot中可以通过接口和不同的实现类来实现策略模式。
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略实现类:信用卡支付
@Component
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " using Credit Card");
}
}
// 具体策略实现类:现金支付
@Component
public class CashPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " using Cash");
}
}
// 上下文类
@Component
public class PaymentContext {
@Autowired
private List<PaymentStrategy> paymentStrategies;
public void setPaymentMethod(String method) {
this.paymentMethod = method;
}
public void pay(double amount) {
for (PaymentStrategy strategy : paymentStrategies) {
if (strategy.getClass().getSimpleName().equalsIgnoreCase(this.paymentMethod)) {
strategy.pay(amount);
break;
}
}
}
private String paymentMethod;
}
6. 模板方法模式(Template Method Pattern)
在Spring Boot中使用模板方法模式(Template Method Pattern)通常涉及创建一个抽象基类,该类定义了一个算法的框架,但将某些步骤的实现留给子类。这样,你可以在不改变算法结构的情况下,通过定义新的子类来改变算法中的某些步骤。
1. 定义抽象基类
首先,你需要创建一个抽象基类,其中包含一个模板方法(通常是final
的,以防止子类覆盖它)和一些抽象方法(或钩子方法,这些可以是具体实现,但允许子类根据需要覆盖它们)。
// AbstractClass.java
public abstract class AbstractClass {
// 模板方法,定义了算法的框架
public final void templateMethod() {
step1();
step2();
hookMethod(); // 钩子方法,允许子类在必要时提供自己的实现
step3();
}
// 抽象方法,由子类实现
protected abstract void step1();
protected abstract void step3();
// 钩子方法,有默认实现,但允许子类覆盖
protected void hookMethod() {
// 默认实现为空,或者提供一些通用的行为
}
// 具体方法,可以包含一些算法的通用步骤
private void step2() {
// 这里是算法的一个具体步骤,通常不需要子类覆盖
}
}
2. 实现具体子类
然后,你需要创建具体子类,这些子类将提供模板方法中抽象方法和钩子方法的具体实现。
// ConcreteClassA.java
public class ConcreteClassA extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreteClassA implementation of step1");
}
@Override
protected void step3() {
System.out.println("ConcreteClassA implementation of step3");
}
// 可以选择覆盖钩子方法以提供额外的行为
// @Override
// protected void hookMethod() {
// System.out.println("ConcreteClassA implementation of hookMethod");
// }
}
// ConcreteClassB.java
public class ConcreteClassB extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreteClassB implementation of step1");
}
@Override
protected void step3() {
System.out.println("ConcreteClassB implementation of step3");
}
// 覆盖钩子方法以提供不同的行为
@Override
protected void hookMethod() {
System.out.println("ConcreteClassB implementation of hookMethod");
}
}
3. 在Spring Boot应用中使用
最后,在你的Spring Boot应用中,你可以像使用任何其他Spring Bean一样使用这些具体子类。你可以通过配置类、@Component
注解或直接在控制器、服务等组件中实例化它们。
// TemplateMethodPatternApplication.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TemplateMethodPatternApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(TemplateMethodPatternApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
AbstractClass concreteClassA = new ConcreteClassA();
AbstractClass concreteClassB = new ConcreteClassB();
// 调用模板方法
concreteClassA.templateMethod();
concreteClassB.templateMethod();
}
}
在这个示例中,TemplateMethodPatternApplication
是我们的Spring Boot应用主类。它创建了两个具体子类的实例,并调用了它们的模板方法。这将按照算法框架执行,并使用子类提供的具体实现。
请注意,虽然在这个例子中我们没有将AbstractClass
及其子类作为Spring Bean来管理,但在实际的应用中,你可能会希望这样做以便利用Spring的依赖注入功能。你可以通过添加@Component
注解并使用@Autowired
或@Bean
注解来将这些类集成到Spring的上下文中。
7. 适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类一起工作。在Spring Boot应用中,你可以使用适配器模式来适配不同接口或类的实现,以便它们可以无缝地协同工作。
下面是一个如何在Spring Boot中使用适配器模式的示例。
假设我们有一个旧的支付服务(LegacyPaymentService),它的接口和新支付服务(NewPaymentService)的接口不兼容。我们需要一个适配器来使它们可以一起工作。
1. 定义旧的支付服务接口和实现
首先,我们定义一个旧的支付服务接口及其实现:
// LegacyPaymentService.java
public interface LegacyPaymentService {
void makeLegacyPayment(double amount);
}
// LegacyPaymentServiceImpl.java
public class LegacyPaymentServiceImpl implements LegacyPaymentService {
@Override
public void makeLegacyPayment(double amount) {
System.out.println("Making legacy payment of: " + amount);
}
}
2. 定义新的支付服务接口和实现
接下来,我们定义一个新的支付服务接口及其实现:
// NewPaymentService.java
public interface NewPaymentService {
void makePayment(double amount);
}
// NewPaymentServiceImpl.java
public class NewPaymentServiceImpl implements NewPaymentService {
@Override
public void makePayment(double amount) {
System.out.println("Making new payment of: " + amount);
}
}
3. 创建适配器类
现在,我们需要创建一个适配器类,它将旧的支付服务适配为新的支付服务:
// LegacyPaymentServiceAdapter.java
public class LegacyPaymentServiceAdapter implements NewPaymentService {
private LegacyPaymentService legacyPaymentService;
public LegacyPaymentServiceAdapter(LegacyPaymentService legacyPaymentService) {
this.legacyPaymentService = legacyPaymentService;
}
@Override
public void makePayment(double amount) {
legacyPaymentService.makeLegacyPayment(amount);
}
}
4. 使用Spring Boot配置和测试
最后,我们在Spring Boot应用中配置这些类并进行测试。
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class PaymentServiceApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(PaymentServiceApplication.class, args);
}
@Bean
public LegacyPaymentService legacyPaymentService() {
return new LegacyPaymentServiceImpl();
}
@Bean
public NewPaymentService newPaymentService(LegacyPaymentService legacyPaymentService) {
return new LegacyPaymentServiceAdapter(legacyPaymentService);
}
@Override
public void run(String... args) throws Exception {
NewPaymentService paymentService = newPaymentService();
paymentService.makePayment(100.0);
}
}
在这个示例中,PaymentServiceApplication
类是我们的Spring Boot应用主类。它定义了两个Bean:legacyPaymentService
和newPaymentService
。newPaymentService
是通过LegacyPaymentServiceAdapter
适配的legacyPaymentService
。
当运行Spring Boot应用时,run
方法会被调用,并且适配器会将新的支付请求转换为旧的支付请求,并输出相应的日志。
8. 装饰者模式(Decorator Pattern)
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地将责任附加到对象上,而无需修改其现有的代码。在Spring Boot应用中,你可以使用装饰者模式来增强或修改对象的行为,而无需使用继承或创建大量的子类。
1. 定义组件接口
首先,我们定义一个接口,该接口将作为要装饰的对象的基类或接口。
// PaymentComponent.java
public interface PaymentComponent {
void pay(double amount);
}
2. 实现基础组件
接下来,我们实现这个接口的基础版本,即不添加任何装饰的组件。
// SimplePayment.java
public class SimplePayment implements PaymentComponent {
@Override
public void pay(double amount) {
System.out.println("Paid: " + amount);
}
}
3. 创建装饰者基类
现在,我们创建一个装饰者基类,它实现了相同的接口,并持有一个被装饰对象的引用。
// PaymentDecorator.java
public abstract class PaymentDecorator implements PaymentComponent {
protected PaymentComponent paymentComponent;
public PaymentDecorator(PaymentComponent paymentComponent) {
this.paymentComponent = paymentComponent;
}
@Override
public abstract void pay(double amount);
}
4. 实现具体的装饰者
然后,我们实现具体的装饰者,这些装饰者将添加额外的行为或修改现有行为。
// LoggingPaymentDecorator.java
public class LoggingPaymentDecorator extends PaymentDecorator {
public LoggingPaymentDecorator(PaymentComponent paymentComponent) {
super(paymentComponent);
}
@Override
public void pay(double amount) {
System.out.println("Logging payment of: " + amount);
paymentComponent.pay(amount);
}
}
// TaxPaymentDecorator.java
public class TaxPaymentDecorator extends PaymentDecorator {
private double taxRate;
public TaxPaymentDecorator(PaymentComponent paymentComponent, double taxRate) {
super(paymentComponent);
this.taxRate = taxRate;
}
@Override
public void pay(double amount) {
double totalAmount = amount * (1 + taxRate);
System.out.println("Applying tax rate of " + (taxRate * 100) + "%");
paymentComponent.pay(totalAmount);
}
}
5. 使用Spring Boot配置和测试
最后,我们在Spring Boot应用中配置这些类并进行测试。
// PaymentServiceApplication.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class PaymentServiceApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(PaymentServiceApplication.class, args);
}
@Bean
public PaymentComponent simplePayment() {
return new SimplePayment();
}
@Bean
public PaymentComponent decoratedPayment(PaymentComponent simplePayment, double taxRate) {
PaymentComponent loggingPayment = new LoggingPaymentDecorator(simplePayment);
return new TaxPaymentDecorator(loggingPayment, taxRate);
}
@Override
public void run(String... args) throws Exception {
PaymentComponent paymentComponent = decoratedPayment(simplePayment(), 0.10); // 10% tax rate
paymentComponent.pay(100.0);
}
}
在这个示例中,PaymentServiceApplication
类是我们的Spring Boot应用主类。它定义了两个Bean:simplePayment
和decoratedPayment
。decoratedPayment
是通过组合LoggingPaymentDecorator
和TaxPaymentDecorator
来装饰simplePayment
的。
然而,需要注意的是,在Spring容器中直接这样配置decoratedPayment
Bean可能会有些复杂,因为我们需要传递一个double
类型的taxRate
参数。在实际应用中,你可能会使用配置属性、环境变量或其他方式来传递这个参数。
为了简化示例,这里直接在run
方法中创建了装饰后的对象。但在实际生产环境中,你应该通过配置或注入的方式来管理这些Bean的依赖关系。
9. 原型模式(Prototype Pattern)
原型模式用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。在Spring中,可以通过实现PrototypeBeanFactory
来创建原型Bean。
// 原型Bean类
public class PrototypeBean implements Cloneable {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 配置类
@Configuration
public class AppConfig {
@Bean
@Scope("prototype")
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}
}