工厂模式、单例模式、装饰模式、策略模式、代理模式和观察者模式
1.工厂模式
实际应用场景
工厂方法在SpringBoot中,如果在用工厂的同时又出现了new,那绝对是一个败笔。在SpringBoot中,几乎所有对象都可以直接交给Spring容器管理,它天然已经是一个工厂对象,因此在SpringBoot项目中用工厂模式,再频繁new对象反而不妥。那么工厂模式究竟怎么用在SpringBoot项目的支付场景呢?其实很简单,如果我们要选择一个支付渠道,而项目中有100种支付渠道,那这个时候无疑要写100个@Autowired 注入100个支付渠道,并且需要做100种判断,这个时候我们可以用工厂模式取代我们判断,直接根据我们配置的映射关系从Spring容器中拿到对应支付渠道的实例,代码量将大大减少,这块是使用工厂的另一种秒用。
模拟场景
工厂方法模式包含如下角色:
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
结构图:
时序图
工厂模式总结
(1)适用场景
输出的产品是标准品,谁来做都可以。
(2)举例
常见的数据库连接工厂,SqlSessionFactory,产品是一个数据库连接,至于是oracle提供的,还是mysql提供的,我并不需要关心,因为都能让我通过sql来操作数据。
(3)注意事项
项目初期,软件结构和需求都没有稳定下来时,不建议使用此模式,因为其劣势也很明显,增加了代码的复杂度,增加了调用层次,增加了内存负担。所以要注意防止模式的滥用。
(4)简单实现
public class FactoryPatternDemo {
public static void main(String[] args) {
Factory factory = new ConcreteFactoryB();
Product product = factory.createProduct();
product.use();
}
}
//抽象产品:提供了产品的接口
interface Product
{
public void use;
}
//具体产品A:实现抽象产品中的抽象方法
class ConcreteProductA implements Product
{
public void use()
{
System.out.println("具体产品A显示...");
}
}
//具体产品B:实现抽象产品中的抽象方法
class ConcreteProductB implements Product
{
public void use()
{
System.out.println("具体产品B显示...");
}
}
//抽象工厂:提供了厂品的生成方法
interface Factory
{
public Product createProduct();
}
//具体工厂A:实现了厂品的生成方法
class ConcreteFactoryA implements AbstractFactory
{
public Product createProduct()
{
System.out.println("具体工厂A生成-->具体产品A.");
return new ConcreteProductA();
}
}
//具体工厂B:实现了厂品的生成方法
class ConcreteFactoryB implements AbstractFactory
{
public Product createProduct()
{
System.out.println("具体工厂B生成-->具体产品B.");
return new ConcreteProductB();
}
}
实际场景,在springboot中需要根据不同的情况使用不同的支付方式
工厂
@Data
@Configuration
public class PayFactory implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
PayFactory.applicationContext = applicationContext;
}
//根据不同的key获取到不同的bean,从而实现不同的支付方式
public PayChannel createChannel(String key) {
return applicationContext.getBean(key, PayChannel.class);
}
}
public interface PayChannel {
void pay();
}
@Component("weixinPay")
public class WeixinPay implements PayChannel {
@Override
public void pay() {
System.out.println("微信支付");
}
}
@Component("aliPay")
public class AliPay implements PayChannel {
@Override
public void pay() {
System.out.println("支付宝支付");
}
}
@RestController
public class PayController {
@Autowired
private PayFactory payFactory;
@GetMapping("/pay")
public void pay(){
PayChannel channel = payFactory.createChannel("1");
channel.pay();
}
}
2.单例模式
概念:
什么是单例模式?
单例模式是一种创建型设计模式,用于确保一个类只有一个实例,并提供全局访问点来获取该实例。简单来说,单例模式就是通过限制类的实例化次数,使得该类只能被实例化一次。
在单例模式中,类的构造方法通常会被设置为私有,以防止外部直接创建该类的实例。同时,该类内部会定义一个静态方法或成员变量来获取唯一的实例。
单例模式的主要目的是确保系统中只存在一个实例,这样可以节省资源并提高性能。常见的应用场景包括数据库连接池、线程池、日志记录器等需要全局访问且实例唯一的情况。
经典的单例模式实现方式是懒汉式和饿汉式。懒汉式在首次使用时才创建实例,而饿汉式在类加载时就创建实例。懒汉式相对于饿汉式更加延迟实例化,但需要考虑多线程下的线程安全性。
优点:
- 独一无二的实例:通过单例模式,确保一个类只有一个实例存在。这可以避免不同部分的代码创建出多个相同的实例,保证实例的唯一性。
- 全局访问点:单例模式提供了一个全局的访问点,使得其他对象可以方便地获取到该单例实例。这简化了对象之间的通信和数据共享。
- 节约资源:由于单例模式只创建一个实例并重复使用,可以减少系统中相同对象的创建和销毁过程,从而节约了系统资源。
- 惰性实例化:懒汉式单例模式在首次使用时才创建实例,避免了不必要的资源浪费。当实例对象较为复杂或初始化耗时较长时,惰性实例化可以提升系统启动速度。
- 避免竞态条件:单例模式可以通过合适的实现方式(如双重检查锁定)避免多线程下的竞态条件,确保线程安全性。
- 可控的实例化:通过单例模式,可以对实例化过程进行集中控制,从而更好地管理和维护实例化对象。
1.springboot单例模式
在Spring Boot中实现单例模式,可以使用Spring框架提供的**@Scope**注解。默认情况下,Spring Bean是单例的,因此不需要显式地指定@Scope注解。但是,如果需要更改Bean的作用域,则可以使用@Scope注解。
以下是一个使用@Scope注解实现单例模式的示例:
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public class SingletonBean {
// 单例Bean的代码
}
在上面的示例中,我们使用@Component注解将SingletonBean类标记为Spring Bean,并使用@Scope(“singleton”)注解将其作用域设置为单例。
相关问题
2.springboot启用单例模式
在SpringBoot中,默认情况下,所有的Bean都是以单例模式进行管理的。这意味着在应用程序的整个生命周期中,只会创建一个实例,并且该实例会在需要时被重复使用。
SpringBoot中启用单例模式的方式有以下几种:
- 默认方式:当使用
@Component、@Service、@Repository等注解标记类时,默认情况下会以单例模式进行管理。
@Service
public class UserService {
// ...
}
- 使用
@Scope注解:通过在类级别上使用@Scope("singleton")注解,可以明确指定该类以单例模式进行管理。
@Service
@Scope("singleton")
public class UserService {
// ...
}
- 在配置文件中指定:可以在
application.properties或application.yml配置文件中,设置spring.main.allow-bean-definition-overriding=true来启用单例模式。这样,在使用@Component、@Service、@Repository等注解标记类时,默认会以单例模式进行管理。
需要注意的是,即使启用了单例模式,SpringBoot仍然可以通过其他方式创建非单例的Bean,例如在方法上使用@Scope("prototype")注解来指定原型模式。此外,在多线程环境下,需要注意单例Bean的线程安全性。
3.springboot怎么使用单例模式
在Spring Boot中使用单例模式与使用传统的Java应用程序中使用单例模式是相同的。单例模式是一种创建型设计模式,旨在确保类只有一个实例,并且提供一个全局访问点。在Spring Boot中,可以通过将类标记为组件(使用@Component或其他相关注释)来实现单例模式,Spring Boot会自动管理这些组件的生命周期。
例如,考虑一个名为SingletonService的类,它使用单例模式实现:
@Component
public class SingletonService {
private static SingletonService instance;
private SingletonService() {}
public static synchronized SingletonService getInstance() {
if (instance == null) {
instance = new SingletonService();
}
return instance;
}
public void doSomething() {
System.out.println("Doing something...");
}
}
该示例通过在getInstance方法上添加synchronized关键字确保线程安全,但会对性能造成一定影响。为了避免每次都进行同步,也可以采用双重检查锁定(Double-Checked Locking)或静态内部类的方式实现懒汉式单例模式。
@Service
public class MyService {
@Autowired
private SingletonService singletonService;
public void doSomething() {
singletonService.doSomething();
}
}
这样做可以确保在应用程序中只有一个SingletonService实例,并且可以在需要时被注入到其他组件中使用。
3.装饰模式
装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰器模式的主要优点有:
- 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
- 装饰器模式完全遵守开闭原则
其主要缺点是:装饰器模式会增加许多子类,过度使用会增加程序得复杂性。
1. 装饰器模式的结构与实现
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰器模式的目标。下面来分析其基本结构和实现方法
4.建造者模式
4.1结构
- 抽象建造者
- 具体建造者
- 产品类
- 指挥者类

...