原文鏈接:https://www.cnblogs.com/Alickx/p/16368364.html
Java-SpringBoot-使用多態(tài)給項(xiàng)目解耦
提及
今天在打算維護(hù)一下智慧社區(qū)這個(gè)項(xiàng)目的時(shí)候,想到項(xiàng)目是使用Satoken這個(gè)開箱即用的授權(quán)和認(rèn)證的組件,因?yàn)樵陧?xiàng)目開啟的時(shí)候?qū)pringSecurity并不熟悉,而Satoken類似傻瓜式的,導(dǎo)入依賴進(jìn)去,配置一下獲取權(quán)限和角色的方法即可使用。
但是由此帶來(lái)的問(wèn)題就是,項(xiàng)目中充斥著Satoken的API方法,類似于StpUtil.isLogin(),StpUtil.getLoginIdAsLong()這類方法在Service層中已經(jīng)是相當(dāng)常見(jiàn)了,盡管是非常的方便,但是帶來(lái)的問(wèn)題就是假如后面我要替換另外一款權(quán)限認(rèn)證和授權(quán)的組件,那么這些API方法通通都需要進(jìn)行修改,這種強(qiáng)耦合很明顯是不合理的。
我突然想到在SpringSecurity中,配置密碼加密方法的時(shí)候,我們可以選擇任意的密碼加密方法。
@Beanpublic PasswordEncoder getPasswordEncoder() { return new BCryptPasswordEncoder();}
那么,我能不能也像這樣子,提供一個(gè)統(tǒng)一的接口,通過(guò)選擇實(shí)現(xiàn)方式的不同,從而達(dá)到當(dāng)需要更換別的實(shí)現(xiàn)方式的時(shí)候,只需要更改該處代碼即可。
多態(tài)
其實(shí)這需要利用到Java的三大特性之一,多態(tài)。Java的三大特性分別是封裝,繼承和多態(tài)。
這里使用一個(gè)小例子來(lái)演示一下什么是多態(tài)。
我們先創(chuàng)建一個(gè)接口,這個(gè)接口只需要含有我們統(tǒng)一所需的方法。
/** * @Author: Alickx * @Date: 2022/06/12/16:22 * @Description: 統(tǒng)一接口 */public interface IRun { /** * 跑步 */ void run();}
然后我們需要來(lái)創(chuàng)建幾個(gè)實(shí)現(xiàn)該接口的實(shí)現(xiàn)類
分別是Man.java和Woman.java
/** * @Author: Alickx * @Date: 2022/06/12/16:27 * @Description: 男人的實(shí)現(xiàn)類 */public class Man implements IRun{ @Override public void run() { System.out.println(“我是Man,我在run”); }} /** * @Author: Alickx * @Date: 2022/06/12/16:27 * @Description: 女人的實(shí)現(xiàn)類 */public class Woman implements IRun{ @Override public void run() { System.out.println(“我是Woman,我在run”); }}
接著上面的提及,我們把Man和Woman想成是不同密碼加密方式,而run方法則是他們都需要實(shí)現(xiàn)的密碼加密方法。
那我們?cè)囍屵@幾個(gè)類型實(shí)例化。
/** * @Author: Alickx * @Date: 2022/06/12/9:13 * @Description: main方法 */public class Demo8 { public static void main(String[] args) { // 使用man來(lái)實(shí)例化 IRun human1 = new Man(); human1.run(); // 使用woman來(lái)實(shí)例化 IRun human2 = new Woman(); human2.run(); }}
這里可以看出假如我們要將Man所實(shí)現(xiàn)的run要替換成Woman,我們并不需要修改很多代碼,只需要將IRun human1 = new Man(); 替換成IRun human1 = new Woman(); 即可
實(shí)際項(xiàng)目改造
那使用多態(tài)這種特性,我們就可以創(chuàng)建一個(gè)統(tǒng)一的接口,業(yè)務(wù)代碼都使用這個(gè)接口的方法,而通過(guò)實(shí)現(xiàn)該接口的方法,從而可以選擇多種不同的實(shí)現(xiàn)方式。
那先創(chuàng)建一個(gè)AuthService接口,接口里面包含著我們業(yè)務(wù)代碼所需要的api方法。
然后創(chuàng)建AuthSatokenServiceImpl 實(shí)現(xiàn)類,該實(shí)現(xiàn)類是使用Satoken來(lái)實(shí)現(xiàn)接口里面的方法。
簡(jiǎn)單調(diào)用一下Satoken的Api方法。
那么接口有了,實(shí)現(xiàn)類有了,但是在Springboot項(xiàng)目中,我們將實(shí)例化交給了Spring來(lái)管理,所以還需要?jiǎng)?chuàng)建一個(gè)配置類,來(lái)讓Spring選擇需要實(shí)例化的類。
Ok,那我們直接修改項(xiàng)目中的代碼,這里舉例一處。
原先的業(yè)務(wù)代碼。
想以上紅圈內(nèi)的代碼,我們需要獲取當(dāng)前請(qǐng)求的用戶是否登錄了,假如我們直接使用Satoken的API方法,那么后面需要更換SpringSecurity或者其他一些組件的時(shí)候,就需要大面積的修改這些代碼。
改造后:
先注入實(shí)現(xiàn)類
@AutowiredAuthService authService;
這樣子就完成了解耦,假如需要更換其他的授權(quán)認(rèn)證組件,只需要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)AuthService接口的實(shí)現(xiàn)類,然后修改一下配置類的實(shí)例即可。
更改該處即可,即可更換。