網(wǎng)站首頁 編程語言 正文
設(shè)計模式01-單例和工廠
設(shè)計模式概念
模式是一套被反復使用、多數(shù)人知曉的、經(jīng)過分類編寫的、成功代碼設(shè)計經(jīng)驗的總結(jié);它不是語法規(guī)定,而是一套用來提高代碼可復用性、可維護性、可讀性、穩(wěn)健性以及安全性的解決方案。 (性能,安全,可靠)
設(shè)計模式的作用
- 可以提高程序員的思維能力、編程能力和設(shè)計能力。
- 使程序設(shè)計更加標準化、代碼編制更加工程化,使軟件開發(fā)效率大大提高,從而縮短軟件的開發(fā)周期。
- 使設(shè)計的代碼可重用性高、可讀性強、可靠性高、靈活性好、可維護性強。
設(shè)計模式類別
分為三大類:
- 創(chuàng)建型模式(5種):工廠方法模式,抽象工廠模式,單例模式,建造者模式,原型模式。
- 結(jié)構(gòu)型模式(7種):適配器模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。
- 行為型模式(11種):策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。
設(shè)計模式遵循的原則有7個:
1. 開閉原則(Open Close Principle)
對擴展開放,對修改關(guān)閉。
問題:在軟件的生命周期內(nèi),因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行重構(gòu),并且需要原有代碼經(jīng)過重新測試。
解決方案:當軟件需要變化時,盡量通過擴展軟件實體的行為來實現(xiàn)變化
,而不是通過修改已有的代碼來實現(xiàn)變化。
2. 里氏代換原則(Liskov Substitution Principle)
里氏代換原則(Liskov Substitution Principle LSP)面向?qū)ο笤O(shè)計的基本原則之一。
里氏代換原則中說,任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)。
LSP是繼承復用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現(xiàn)“開-閉”原則的關(guān)鍵步驟就是抽象化。而基類與子類的繼承關(guān)系就是抽象化的具體實現(xiàn),所以里氏代換原則是對實現(xiàn)抽象化的具體步驟的規(guī)范。
問題 :有一功能P1,由類A完成。現(xiàn)需要將功能P1進行擴展,擴展后的功能為P,其中P由原有功能P1與新功能P2組成。新功能P由類A的子類B來完成,則子類B在完成新功能P2的同時,有可能會導致原有功能P1發(fā)生故障。解決方案:當使用繼承時,遵循里氏替換原則。類B繼承類A時,
除添加新的方法完成新增功能P2外,盡量不要重寫父類A的方法,也盡量不要重載父類A的方法
。【有時候我們可以采用final的手段強制來遵循】
3. 依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)
這個是開閉原則的基礎(chǔ),對接口編程,依賴于抽象而不依賴于具體。高層模塊不應(yīng)該依賴低層模塊,兩者都應(yīng)該依賴其抽象。
問題:類A直接依賴類B,假如要將類A改為依賴類C,則必須通過修改類A的代碼來達成。這種場景下,類A一般是高層模塊,負責復雜的業(yè)務(wù)邏輯;類B和類C是低層模塊,負責基本的原子操作;假如修改類A,會給程序帶來不必要的風險。
解決方案:將類A修改為依賴接口I,類B和類C各自實現(xiàn)接口I,類A通過接口I間接與類B或者類C發(fā)生聯(lián)系,則會大大降低修改類A的幾率。
4. 接口隔離原則(Interface Segregation Principle)
使用多個隔離的接口來降低耦合度。
問題:類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對于類A和類B來說不是最小接口,則類B和類D必須去實現(xiàn)他們不需要的方法。
解決方案:將臃腫的接口I拆分為獨立的幾個接口,類A和類C分別與他們需要的接口建立依賴關(guān)系。也就是采用接口隔離原則。
5. 迪米特法則(最少知道原則)(Demeter Principle)
一個實體應(yīng)當盡量少的與其他實體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對獨立。
問題:類與類之間的關(guān)系越密切,耦合度越大,當一個類發(fā)生改變時,對另一個類的影響也越大。
解決方法:盡量降低類與類之間的耦合。
6. 合成復用原則(Composite Reuse Principle)
原則是盡量使用合成/聚合的方式,而不是使用繼承。繼承實際上破壞了類的封裝性,超類的方法可能會被子類修改。
問題:B類如果繼承了A類,A類可繼承方法m的實現(xiàn)細節(jié)暴露給B類,如果A類發(fā)生方法m改變,那么B的實現(xiàn)也不得不發(fā)生改變。
解決方法:使用合成或者聚合,不要使用繼承
7. 單一職責原則(Single responsibility principle)
一個類只負責一個功能領(lǐng)域的響應(yīng)職責。
如果一個類承擔的職責過多,就等于把這些職責耦合在一起,一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。另外,多個職責耦合在一起,會影響復用性。
問題:比如一個類T負責兩個不同的職責:職責P1,職責P2。當由于職責P1需求發(fā)生改變而需要修改類T時,有可能會導致原本運行正常的職責P2功能發(fā)生故障。
解決方法:遵循單一職責原則。分別建立兩個類T1、T2,使T1完成職責P1功能,T2完成職責P2功能。這樣,當修改類T1時,不會使職責P2發(fā)生故障風險;同理,當修改T2時,也不會使職責P1發(fā)生故障風險。
常用設(shè)計模式
工廠模式
工廠模式屬于創(chuàng)建型設(shè)計模式,它提供了一種創(chuàng)建對象的最佳方式
。隱藏復雜的邏輯處理過程, 只關(guān)心執(zhí)行結(jié)果。直接用new可以完成的不需要用工廠模式。在需要生成復雜對象
的地方使用。
靜態(tài)工廠模式
靜態(tài)工廠模式又可以稱為簡單工廠模式
概念:在簡單工廠模式中,可以根據(jù)參數(shù)的不同返回不同類的實例。簡單工廠模式專門定義一個類來負責創(chuàng)建其他類的實例,被創(chuàng)建的實例通常都具有共同的父類。(生成同類型產(chǎn)品)
優(yōu)點:功能強大,對象創(chuàng)建和使用分離,程序員可以只關(guān)心對象使用,不用關(guān)心對象如何創(chuàng)建
。
缺點:耦合度高(所有產(chǎn)品都在工廠創(chuàng)建,一旦異常其他產(chǎn)品也受影響),擴展性不強(每次添加一個產(chǎn)品,工廠類都要變化)
,違背開閉原則 。
- 定義接口
package com.aaa.fatory;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 14:52
* @description:學習軟件開發(fā)技術(shù)
* @modified By:
* @version: 1.0
*/
public interface SoftwareTechnology {
void studyST();
}
-
編寫實現(xiàn)類
-
測試
@Test
public void staticFactoryTest(){
SoftwareTechnology java = TechnologyFactory.teach(1);
java.studyST();
SoftwareTechnology python = TechnologyFactory.teach(2);
python.studyST();
}
兩個對象都被創(chuàng)建出來了
工廠(方法)模式:
工廠方法模式定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。
概念解釋:
工廠本身不再創(chuàng)建產(chǎn)品,而是規(guī)定了工廠規(guī)范,即工廠接口,而將產(chǎn)品創(chuàng)建都交給子工廠創(chuàng)建。
優(yōu)點: 遵循了開閉原則(不需要修改工廠類,就可以增加產(chǎn)品 解耦,職責單一
(每個工廠只負責創(chuàng)建對應(yīng)的產(chǎn)品)
缺點: 增加系統(tǒng)復雜度(每新加一個產(chǎn)品需要新加一個工廠)
- 定義工廠接口
package com.aaa.designmode.factory;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 15:04
* @description:總工廠,相當于總公司,只定義規(guī)范 ,不參與生產(chǎn)
* @modified By:
* @version:
*/
public interface TechnologyFactoryInterface {
/**
* 生產(chǎn)規(guī)范,教學規(guī)范
*/
SoftwareTechnology teachST();
}
- 編寫工廠實現(xiàn)類
package com.aaa.designmode.factory;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 15:06
* @description:
* @modified By:
* @version:
*/
public class ZhengZhouFactory implements TechnologyFactoryInterface{
@Override
public SoftwareTechnology teachST() {
return new JavaTechnology();
}
}
package com.aaa.designmode.factory;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 15:06
* @description:
* @modified By:
* @version:
*/
public class WuHanFactory implements TechnologyFactoryInterface{
@Override
public SoftwareTechnology teachST() {
return new PythonTechnology();
}
}
測試
@Test
public void factoryMethodTest(){
//學Java
TechnologyFactoryInterface zhengZhouFactory = new ZhengZhouFactory();
SoftwareTechnology softwareTechnology1 = zhengZhouFactory.teachST();
softwareTechnology1.studyST();
//學python
TechnologyFactoryInterface wuHanFactory = new WuHanFactory();
SoftwareTechnology softwareTechnology2 = wuHanFactory.teachST();
softwareTechnology2.studyST();
}
同樣兩個對象也被創(chuàng)建出來了
抽象工廠
概念:抽象工廠是工廠方法的升級版,為相關(guān)或者相互依賴的對象提供一個接口,而且無須指定他們的具體實現(xiàn)類。
概念解釋:抽象工廠模式相對于工廠方法模式來說,就是工廠方法模式是針對一個產(chǎn)品系列的,而抽象工廠模式是針對多個產(chǎn)品系列的,即工廠方法模式是一個產(chǎn)品系列一個工廠類,而抽象工廠模式是多個產(chǎn)品系列一個工廠類
優(yōu)點:當一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象。
缺點:難以支持新種類的產(chǎn)品。因為抽象工廠接口確定了可以被創(chuàng)建的產(chǎn)品集合,所以難以擴展抽象工廠以生產(chǎn)新種類的產(chǎn)品。
- 定義抽象接口(包括簡單和工廠方法)
package com.aaa.fatory;
/**
* @author : Student尚
* @version : 1.0
* @createTime : 2022/9/25 18:31
* @description :
*/
public interface HardwareTechnology {
void studyHT();
}
package com.aaa.designmode.factory;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 15:04
* @description:
* @modified By:
* @version:
*/
public interface TechnologyFactoryAbstractInterface {
/**
* 生產(chǎn)規(guī)范,返回軟件技術(shù)
*/
SoftwareTechnology teachST();
/**
* 生產(chǎn)規(guī)范,返回硬件技術(shù)
*/
HardwareTechnology teachHT();
}
- 編寫實現(xiàn)工廠
package com.aaa.designmode.factory;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 15:06
* @description:
* @modified By:
* @version:
*/
public class ZhengZhouFactoryNew implements TechnologyFactoryAbstractInterface{
@Override
public SoftwareTechnology teachST() {
return new JavaTechnology();
}
@Override
public HardwareTechnology teachHT() {
return new PhoneTechnology();
}
}
測試
@Test
public void factoryAbstract(){
TechnologyFactoryAbstractInterface tfai = new ZhengZhouFactoryNew();
SoftwareTechnology softwareTechnology = tfai.teachST();
softwareTechnology.studyST();
HardwareTechnology hardwareTechnology = tfai.teachHT();
hardwareTechnology.studyHT();
}
總結(jié):
無論是簡單工廠模式,工廠方法模式,還是抽象工廠模式,他們都屬于工廠模式,在形式和特點上也是極為相似的,他們的最終目的都是為了解耦,讓類的創(chuàng)建和使用過程實現(xiàn)松耦合。
單例(態(tài))模式
概念:
一種常用的軟件設(shè)計模式。所謂單例,就是讓一個類在項目運行中只存在一個對象,即使用到這個類的地方很多,也只存在一個對象。
好處:
- 節(jié)省內(nèi)存
- 有些情況下不用單例模式可能會引起代碼邏輯錯誤(例如:網(wǎng)站訪問量統(tǒng)計功能 application.setAttrbute(“count”,100);
單例模式要點:
- 單例模式的類只提供私有的構(gòu)造函數(shù)
- 類定義中含有一個該類的靜態(tài)私有對象;
- 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
實現(xiàn)方式(7種):
懶漢(slacker):該單例類非常懶,只有在自身需要的時候才會行動
,從來不知道及早做好準備。特點是運行時獲得對象的速度比較慢,但加載類的時候比較快。整個應(yīng)用的生命周期只有一部分時間在占用資源。
1. 懶漢線程不安全:
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:09
* @description:
* @modified By:
* @version:
*/
public class SlackerSingleton {
/**
* 1、構(gòu)造器私有
*/
private SlackerSingleton() {
}
/**
* 2. 類定義中含有一個該類的靜態(tài)私有對象;
*/
private static SlackerSingleton singleton;
/**
* 3. 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
*/
public static SlackerSingleton getInstance(){
if(singleton ==null){
singleton = new SlackerSingleton();
}
return singleton;
}
}
測試:
@Test
public void singletonTest(){
Person person1 = new Person();
Person person2 = new Person();
//普通類new出來的內(nèi)存區(qū)域不同,所以下面的返回值為false
System.out.println(person1==person2);
SlackerSingleton singleton1 = SlackerSingleton.getInstance();
SlackerSingleton singleton2 = SlackerSingleton.getInstance();
System.out.println(singleton1==singleton2);
}
2. 懶漢線程安全
上面的getinstance()方法在單線程的場景下不會出現(xiàn)問題,但是在多線程場景下,會出現(xiàn)線程安全問題。
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:09
* @description:
* @modified By:
* @version:
*/
public class SlackerSingleton {
/**
* 1、構(gòu)造器私有
*/
private SlackerSingleton() {
}
/**
* 2. 類定義中含有一個該類的靜態(tài)私有對象;
*/
private static SlackerSingleton singleton;
/**
* 3. 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
*/
public static SlackerSingleton getInstance(){
if(singleton ==null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SlackerSingleton();
}
return singleton;
}
}
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:06
* @description:
* @modified By:
* @version:
*/
public class TestSingleton {
public static void main(String[] args) {
Runnable r1= () -> {
SlackerSingleton instance = SlackerSingleton.getInstance();
System.out.println(instance);
};
Runnable r2= () -> {
SlackerSingleton instance = SlackerSingleton.getInstance();
System.out.println(instance);
};
for (int i = 0; i < 20; i++) {
new Thread(r1).start();
new Thread(r2).start();
}
}
}
多線程測試不要在Test方法里測,要在main方法測試,有可能測試失敗(已踩坑)
可以發(fā)現(xiàn)內(nèi)存地址不一致,說明不是單例的。
解決方案:加同步鎖
package com.aaa.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:09
* @description:
* @modified By:
* @version:
*/
public class SlackerSingleton {
/**
* 1、構(gòu)造器私有
*/
private SlackerSingleton() {
}
/**
* 2. 類定義中含有一個該類的靜態(tài)私有對象;
*/
private static SlackerSingleton singleton;
/**
* 3. 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
*/
public static synchronized SlackerSingleton getInstance(){
if(singleton == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
singleton = new SlackerSingleton();
}
return singleton;
}
}
同樣的測試代碼:
3. 懶漢線程安全雙重加鎖(難點)
此代碼看上去沒什么問題,但是在同一時間多線程的情況下,可能出現(xiàn)JVM指令重排的問題,從而導致某一個線程獲取的單例對象沒有初始化對象。
指令重排
指令重排為了提高性能,在遵守 as-if-serial 語義(即不管怎么重排序,單線程下程序的執(zhí)行結(jié)果不能被改變。編譯器,runtime 和處理器都必須遵守。)的情況下,編譯器和處理器常常會對指令做重排序。
一般重排序可以分為如下三種類型:
編譯器優(yōu)化重排序:編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執(zhí)行順序。
指令級并行重排序:現(xiàn)代處理器采用了指令級并行技術(shù)來將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴性,處理器可以改變語句對應(yīng)機器指令的執(zhí)行順序。
內(nèi)存系統(tǒng)重排序:由于處理器使用緩存和讀 / 寫緩沖區(qū),這使得加載和存儲操作看上去可能是在亂序執(zhí)行。
int a = 0;
// 線程 A
a = 1; // 1
boolen flag = true; // 2
// 線程 B
if (flag) { // 3
int i = a; // 4
}
單看上面的程序好像沒有問題,最后 i 的值是 1。但是為了提高性能,編譯器和處理器常常會在不改變數(shù)據(jù)依賴的情況下對指令做重排序。
?
假設(shè)線程 A 在執(zhí)行時被重排序成先執(zhí)行代碼 2,再執(zhí)行代碼 1; 而線程 B 在線程 A 執(zhí)行完代碼 2 后,讀取了 flag變量。由于條件判斷為真,線程 B 將讀取變量 a。此時,變量 a 還根本沒有被線程 A 寫入,那么 i 最后的值是 0,導致執(zhí)行結(jié)果不正確。
?
那么如何程序執(zhí)行結(jié)果正確呢?這里可以使用 volatile 關(guān)鍵字。
?
這個例子中, 使用 volatile 不僅保證了變量的內(nèi)存可見性,還禁止了指令的重排序,即保證了 volatile 修飾的變量編譯后的順序與程序的執(zhí)行順序一樣。那么使用 volatile 修飾 flag 變量后,在線程 A 中,保證了代碼 1 的執(zhí)行順序一定在代碼 2 之前。
volatile 禁止編譯器進行指令重排
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:09
* @description:
* @modified By:
* @version:
*/
public class SlackerSingleton {
/**
* 1、構(gòu)造器私有
*/
private SlackerSingleton() {
}
/**
* 2. 類定義中含有一個該類的靜態(tài)私有對象;
* volatile 禁止編譯器進行指令重排
*/
private volatile static SlackerSingleton singleton;
/**
* 3. 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
*/
public static synchronized SlackerSingleton getInstance(){
if(singleton ==null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SlackerSingleton();
}
return singleton;
}
}
4. 餓漢線程安全
餓漢(starving):該單例類非常餓,迫切需要吃東西,所以它在類加載的時候就立即創(chuàng)建對象。特點是加載類的時候比較慢,但運行時獲得對象的速度比較快。從加載到應(yīng)用結(jié)束會一直占用資源。
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:09
* @description:餓漢式單例模式
* @modified By:
* @version:
*/
public class StarvingSingleton {
/**
* 1、構(gòu)造器私有
*/
private StarvingSingleton() {
}
/**
* 2. 類定義中含有一個該類的靜態(tài)私有對象;
*/
private final static StarvingSingleton singleton= new StarvingSingleton();
/**
* 3. 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
*/
public static StarvingSingleton getInstance(){
return singleton;
}
}
測試
public static void main(String[] args) {
StarvingSingleton ss1 = StarvingSingleton.getInstance();
StarvingSingleton ss2 = StarvingSingleton.getInstance();
System.out.println(ss1==ss2);
}
結(jié)果為true
5. 餓漢靜態(tài)線程安全
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 16:09
* @description:餓漢式單例模式
* @modified By:
* @version:
*/
public class StarvingSingleton {
/**
* 1、構(gòu)造器私有
*/
private StarvingSingleton() {
}
/**
* 2. 類定義中含有一個該類的靜態(tài)私有對象;
*/
private final static StarvingSingleton singleton;
/**
* 靜態(tài)代碼塊
*/
static {
singleton = new StarvingSingleton();
}
/**
* 3. 該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象。
*/
public static StarvingSingleton getInstance(){
return singleton;
}
}
6. 枚舉單例模式
什么是枚舉類型?
jdk1.5之后出現(xiàn)的一種java類型,可以提前知道一個類的對象個數(shù)。
例如一年四季,提前知道四個季節(jié),不會再出現(xiàn)第五個季節(jié)。
第一種構(gòu)建枚舉類型的方式,借鑒單例(餓漢式)
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 17:02
* @description:季節(jié)
* @modified By:
* @version:
*/
public class Season {
private Season(){
}
public static final Season Spring= new Season();
public static final Season Summer= new Season();
public static final Season Autumn= new Season();
public static final Season Winter= new Season();
}
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 17:07
* @description:
* @modified By:
* @version:
*/
public enum SeasonEnum {
Spring,
Summer,
Autumn,
Winter
}
測試
public static void main(String[] args) {
Season season1 = Season.Spring;
Season season2 = Season.Spring;
System.out.println(season1==season2);
}
7. 靜態(tài)內(nèi)部類
package com.aaa.designmode.singleton;
/**
* @author :Teacher陳
* @date :Created in 2022/9/24 17:14
* @description:靜態(tài)內(nèi)部類單例模式
* @modified By:
* @version: 1.0
*/
public class StatticInnerSingleton {
/**
* 1、私有化構(gòu)造器
*/
private StatticInnerSingleton() {
}
/**
* 2、靜態(tài)內(nèi)部類
*/
static class TempClass{
private final static StatticInnerSingleton singleton=new StatticInnerSingleton();
}
/**
* 3、公有的靜態(tài)獲取實例的方法
*/
public static StatticInnerSingleton getInstance(){
return TempClass.singleton;
}
}
原文鏈接:https://blog.csdn.net/qq_60969145/article/details/127040383
相關(guān)推薦
- 2022-03-27 Python的輸出格式化和進制轉(zhuǎn)換介紹_python
- 2023-01-19 GO語言的map類型實例詳解_Golang
- 2022-05-09 Python?matplotlib繪制實時數(shù)據(jù)動畫_python
- 2022-03-27 MongoDB4.28開啟權(quán)限認證配置用戶密碼登錄功能_MongoDB
- 2023-02-06 Go語言基礎(chǔ)學習之數(shù)組的使用詳解_Golang
- 2022-04-07 C++11生成隨機數(shù)(random庫)的使用_C 語言
- 2022-06-14 ASP.NET?Core?MVC中的布局(Layout)_基礎(chǔ)應(yīng)用
- 2023-10-26 video標簽未自動播放,autoplay無效,video不能自動播放的原因分析
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支