亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot中優(yōu)雅的編寫服務(wù)工廠的方法示例

 更新時(shí)間:2025年08月08日 10:54:15   作者:磊磊落落  
在基于 pringBoot的業(yè)務(wù)開發(fā)中,我們有時(shí)會(huì)遇到這樣的場景:即定義了一個(gè)通用接口,而該接口擁有多個(gè)實(shí)現(xiàn)類,在調(diào)用這些實(shí)現(xiàn)類時(shí),我們通常需要編寫一個(gè)工廠方法,下面就拉介紹一下如何實(shí)現(xiàn)

在基于 Spring Boot 的業(yè)務(wù)開發(fā)中,我們有時(shí)會(huì)遇到這樣的場景:即定義了一個(gè)通用接口,而該接口擁有多個(gè)實(shí)現(xiàn)類。在調(diào)用這些實(shí)現(xiàn)類時(shí),我們通常需要編寫一個(gè)工廠方法,該工廠方法可以根據(jù)指定的參數(shù)獲取到對(duì)應(yīng)的實(shí)現(xiàn)類。

那么,提供該工廠方法的類就是一個(gè)服務(wù)工廠,本文即是探討如何優(yōu)雅的編寫這個(gè)服務(wù)工廠。

1 場景描述

為了將所描述的場景具像化,下面舉一個(gè)易于理解的例子:「假定我們正在使用 Spring Boot 做一個(gè)對(duì)接多個(gè)第三方支付平臺(tái)的支付服務(wù)?!?/p>

我們?cè)趯?shí)現(xiàn)這個(gè)支付服務(wù)時(shí),定義了一個(gè)通用的支付接口 PaymentService,其擁有一個(gè) pay() 方法。該接口可以對(duì)訂單(Order)進(jìn)行支付,支付后會(huì)得到一個(gè)支付結(jié)果 PaymentResult

public interface PaymentService {
    PaymentResult pay(Order order);
}

public class Order {
}

public class PaymentResult {
    private boolean success;
    private String message;
}

目前這個(gè)支付服務(wù)需要支持三種支付類型:Alibaba、WeChat 和銀聯(lián)。

public enum PaymentType {
    ALIBABA,
    WECHAT,
    UNION
}

那么 PaymentService 就會(huì)擁有三個(gè)不同的實(shí)現(xiàn)類:AlibabaPaymentServiceImpl、WechatPaymentServiceImplUnionPaymentServiceImpl

@Service("alibabaPaymentService")
public class AlibabaPaymentServiceImpl implements PaymentService {
    @Override
    public PaymentResult pay(Order order) {
        return ...;
    }
}

@Service("wechatPaymentService")
public class WechatPaymentServiceImpl implements PaymentService {
    @Override
    public PaymentResult pay(Order order) {
        return ...;
    }
}

@Service("unionPaymentService")
public class UnionPaymentServiceImpl implements PaymentService {
    @Override
    public PaymentResult pay(Order order) {
        return ...;
    }
}

為了方便調(diào)用,我們需要編寫一個(gè)工廠類 PaymentFactory,其能夠提供一個(gè)方法:可以根據(jù)不同的支付類型(PaymentType)獲取到 PaymentService 的具體實(shí)現(xiàn)。

public class PaymentFactory {

    public PaymentService getService(PaymentType paymentType) {
        return xxx;
    }
}

這樣調(diào)用者需要使用某種方式進(jìn)行支付時(shí),只需要指定支付類型,通過工廠類拿到 PaymentService,然后調(diào)用 pay() 方法就可以了。

PaymentService paymentService = paymentFactory.getService(PaymentType.WECHAT);
PaymentResult paymentResult = paymentService.pay(new Order());

System.out.println(paymentResult);

2 PaymentFactory 基礎(chǔ)實(shí)現(xiàn)

那么如何編寫這個(gè) PaymentFactory 呢?一種最基礎(chǔ)的寫法就是在 PaymentFactory 中將 PaymentService 所有的實(shí)現(xiàn)類都以屬性的方式注入進(jìn)來,然后在 getService() 方法中使用 if-elseswitch 語句根據(jù) PaymentType 來返回不同的實(shí)現(xiàn)類。

@Component
public class PaymentFactory {

    @Qualifier("alibabaPaymentService")
    @Autowired
    private PaymentService alibabaPaymentService;

    @Qualifier("wechatPaymentService")
    @Autowired
    private PaymentService wechatPaymentService;

    @Qualifier("unionPaymentService")
    @Autowired
    private PaymentService unionPaymentService;

    public PaymentService getService(PaymentType paymentType) {
        return switch (paymentType) {
            case ALIBABA -> alibabaPaymentService;
            case WECHAT -> wechatPaymentService;
            case UNION -> unionPaymentService;
            default -> throw new IllegalArgumentException("PaymentType is not supported");
        };
    }
}

這種寫法能用,但代碼行數(shù)有點(diǎn)多且有點(diǎn)笨拙,有沒有更高級(jí)一點(diǎn)的寫法呢?

3 PaymentFactory 高級(jí)實(shí)現(xiàn)

PaymentFactory 稍微高級(jí)一點(diǎn)的寫法是不用將實(shí)現(xiàn)類一一聲明為屬性,且不使用上述諸如 if-elseswitch 等條件判斷語句來根據(jù)不同參數(shù)返回不同的實(shí)現(xiàn)。

而是聲明一個(gè)存放 PaymentType 和實(shí)現(xiàn)類的 Map,然后在構(gòu)造方法中將實(shí)現(xiàn)類注入為方法參數(shù),然后建立該 Map,這樣在 getService() 方法中只需根據(jù) PaymentTypeMap 中直接獲取實(shí)現(xiàn)類即可。

@Component
public class PaymentFactory {

    private final Map<PaymentType, PaymentService> paymentServices;

    @Autowired
    public PaymentFactory(
            @Qualifier("alibabaPaymentService") PaymentService alibabaPaymentService,
            @Qualifier("wechatPaymentService") PaymentService wechatPaymentService,
            @Qualifier("unionPaymentService") PaymentService unionPaymentService) {
        paymentServices = Map.of(
                PaymentType.ALIBABA, alibabaPaymentService,
                PaymentType.WECHAT, wechatPaymentService,
                PaymentType.UNION, unionPaymentService
        );
    }

    public PaymentService getService(PaymentType paymentType) {
        return Optional.ofNullable(paymentServices.get(paymentType))
                .orElseThrow(() -> new IllegalArgumentException("PaymentType is not supported"));
    }
}

上面的實(shí)現(xiàn)比較優(yōu)雅,但代碼行數(shù)仍有點(diǎn)多,有沒有更簡便的寫法呢?

有。因?yàn)?PaymentService 的實(shí)現(xiàn)類命名是有規(guī)則的,所以更簡便的寫法即是借助 Spring BeanFactory 直接根據(jù) Bean 名稱獲取對(duì)應(yīng)的實(shí)現(xiàn)。

@Component
public class PaymentFactory {

    @Autowired
    private BeanFactory beanFactory;

    public PaymentService getService(PaymentType paymentType) {
        String beanName = paymentType.name().toLowerCase() + "PaymentService";
        if (!beanFactory.containsBean(beanName)) {
            throw new IllegalArgumentException("PaymentType is not supported");
        }
        return (PaymentService) beanFactory.getBean(beanName);
    }
}

上述代碼的確簡潔了不少,但其與前面的寫法均有一個(gè)同樣的問題,即類上均含有 @Component 注解,即均需要交給 Spring 實(shí)例化。在靜態(tài)方法或由 Java 反射實(shí)例化的類中無法直接使用。

下面就嘗試編寫一個(gè)純靜態(tài)的 PaymentFactory,使得調(diào)用者可以直接像下面這樣通過 PaymentFactory.getService() 的方式獲取 PaymentService 的實(shí)現(xiàn)類。

PaymentService paymentService = PaymentFactory.getService(PaymentType.WECHAT);

這樣就需要依賴一個(gè)保存 Spring 應(yīng)用上下文的工具類了:

@Component
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static <T> T getBean(String beanName, Class<T> clazz) {
        return context.getBean(beanName, clazz);
    }
}

SpringContextHolder 工具類可以在 Spring 加載完成后自動(dòng)持有 Spring 的 ApplicationContext。然后在后期有需要時(shí),調(diào)用者可以使用一個(gè)純靜態(tài)方法來獲取任意 Spring 管理的 Bean。

這樣,有了 SpringContextHolder 工具類后,我們的靜態(tài) PaymentFactory 就可以像下面這樣實(shí)現(xiàn)了。

public class PaymentFactory {

    public static PaymentService getService(PaymentType paymentType) {
        String beanName = paymentType.name().toLowerCase() + "PaymentService";
        return SpringContextHolder.getBean(beanName, PaymentService.class);
    }
}

4 小結(jié)

綜上,本文提出了如何在 Spring Boot 中編寫一個(gè)服務(wù)工廠的問題。然后針對(duì)該問題,舉了一個(gè)支付業(yè)務(wù)的例子,然后探索了 PaymentFactory 的基本寫法和更高級(jí)的寫法。以備有需要的同學(xué)在實(shí)際開發(fā)中做參考。

到此這篇關(guān)于SpringBoot中優(yōu)雅的編寫服務(wù)工廠的方法示例的文章就介紹到這了,更多相關(guān)SpringBoot服務(wù)工廠內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java?Long類型轉(zhuǎn)為json后數(shù)據(jù)損失精度的處理方式

    java?Long類型轉(zhuǎn)為json后數(shù)據(jù)損失精度的處理方式

    這篇文章主要介紹了java?Long類型轉(zhuǎn)為json后數(shù)據(jù)損失精度的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 老程序員教你一天時(shí)間完成Java迷宮小游戲

    老程序員教你一天時(shí)間完成Java迷宮小游戲

    最近經(jīng)常在機(jī)房看同學(xué)在玩一個(gè)走迷宮的游戲,比較有趣,自己也用java寫一個(gè)實(shí)現(xiàn)隨機(jī)生成迷宮的算法,其實(shí)就是一個(gè)圖的深度優(yōu)先遍歷算法.
    2021-08-08
  • 最新Java?泛型中的通配符講解

    最新Java?泛型中的通配符講解

    Java的泛型是偽泛型,那是因?yàn)榉盒托畔⒅淮嬖谟诖a編譯階段,在生成的字節(jié)碼中是不包含泛型中的類型信息的,使用泛型的時(shí)候加上類型參數(shù),在編譯器編譯的時(shí)候會(huì)去掉,這個(gè)過程為類型擦除,這篇文章主要介紹了Java?泛型中的通配符,需要的朋友可以參考下
    2022-06-06
  • SpringBoot訪問請(qǐng)求404解決方法

    SpringBoot訪問請(qǐng)求404解決方法

    這篇文章主要介紹了SpringBoot訪問請(qǐng)求404解決方法,文中有詳細(xì)的解決方法供大家參考,對(duì)我們學(xué)習(xí)或工作有一定的幫助,需要的朋友跟著小編一起來學(xué)習(xí)吧
    2023-07-07
  • SpringCloud大文件分片斷點(diǎn)上傳實(shí)現(xiàn)原理

    SpringCloud大文件分片斷點(diǎn)上傳實(shí)現(xiàn)原理

    這篇文章主要介紹了SpringCloud大文件分片斷點(diǎn)上傳實(shí)現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Java的接口和抽象類深入理解

    Java的接口和抽象類深入理解

    這篇文章主要介紹了Java的接口和抽象類深入理解的相關(guān)資料,希望通過本文大家能夠理解應(yīng)用接口與抽象類的使用方法,需要的朋友可以參考下
    2017-09-09
  • Springboot整合thymleaf模板引擎過程解析

    Springboot整合thymleaf模板引擎過程解析

    這篇文章主要介紹了Springboot整合thymleaf模板引擎過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • java 字符串截取的實(shí)例詳解

    java 字符串截取的實(shí)例詳解

    這篇文章主要介紹了java 字符串截取的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • 在Spring中如何處理循環(huán)依賴問題

    在Spring中如何處理循環(huán)依賴問題

    Spring解決循環(huán)依賴的關(guān)鍵在于提前曝光未完全創(chuàng)建的bean,在Spring中創(chuàng)建Bean分為實(shí)例化、屬性填充和初始化三步,循環(huán)依賴的解決思路是先創(chuàng)建A的bean實(shí)例,此時(shí)A是不完整的,用一個(gè)Map保存不完整的A,再創(chuàng)建B,B需要注入A
    2025-01-01
  • 基于mybatis like %%的問題

    基于mybatis like %%的問題

    這篇文章主要介紹了mybatis like %%的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10

最新評(píng)論