👉 這是一個或許對你有用的社群
《專案實戰(影片)》:從書中學,往事上“練” 《網際網路高頻面試題》:面朝簡歷學習,春暖花開 《架構 x 系統設計》:摧枯拉朽,掌控面試高頻場景題 《精進 Java 學習指南》:系統學習,網際網路主流技術棧 《必讀 Java 原始碼專欄》:知其然,知其所以然

👉這是一個或許對你有用的開源專案國產 Star 破 10w+ 的開源專案,前端包括管理後臺 + 微信小程式,後端支援單體和微服務架構。功能涵蓋 RBAC 許可權、SaaS 多租戶、資料許可權、商城、支付、工作流、大屏報表、微信公眾號、CRM 等等功能:
Boot 倉庫:https://gitee.com/zhijiantianya/ruoyi-vue-pro Cloud 倉庫:https://gitee.com/zhijiantianya/yudao-cloud 影片教程:https://doc.iocoder.cn 【國內首批】支援 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 雙版本

一、🌈設計模式介紹
基於 Spring Boot + MyBatis Plus + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/ruoyi-vue-pro 影片教程:https://doc.iocoder.cn/video/
二、常用的設計模式有哪些?🤔
-
策略模式 -
工廠模式 -
單例模式 -
代理模式 -
工廠方法模式 -
觀察者模式 -
模板方法模式 -
介面卡模式
基於 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的後臺管理系統 + 使用者小程式,支援 RBAC 動態許可權、多租戶、資料許可權、工作流、三方登入、支付、簡訊、商城等功能
專案地址:https://github.com/YunaiV/yudao-cloud 影片教程:https://doc.iocoder.cn/video/
三、設計模式簡單實現模板
3.1 策略模式
public
interfaceStrategy{
/**
* 採用策略
*/
Stringstrategy();
/**
* 計算方法邏輯
*/
voidalgorithm();
}
public
classConcreteStrategyAimplementsStrategy{
@Override
publicStringstrategy(){
returnStrategySelector.strategyA.getStrategy();
}
@Override
publicvoidalgorithm(){
System.out.println(
"process with strategyA..."
);
}
}
publicclassConcreteStrategyBimplementsStrategy{
@Override
publicStringstrategy(){
returnStrategySelector.strategyB.getStrategy();
}
@Override
publicvoidalgorithm(){
System.out.println(
"process with strategyB..."
);
}
}
publicclassConcreteStrategyCimplementsStrategy{
@Override
publicStringstrategy(){
returnStrategySelector.strategyC.getStrategy();
}
@Override
publicvoidalgorithm(){
System.out.println(
"process with strategyC..."
);
}
}
@Getter
publicenumStrategySelector{
strategyA(
1
,
"strategyA"
),
strategyB(
2
,
"strategyB"
),
strategyC(
3
,
"strategyC"
);
privateInteger code;
privateString strategy;
StrategySelector(Integer code,String strategy){
this
.code = code;
this
.strategy = strategy;
}
}
publicinterfaceStrategyRunner
{
voidexecute(String strategy)
;
}
public
classStrategyRunnerImplimplementsStrategyRunner{
privatestaticfinalList<Strategy> STRATEGIES =Arrays.asList(newConcreteStrategyA(),newConcreteStrategyB(),newConcreteStrategyC());
privatestaticMap<String,Strategy> STRATEGY_MAP =Maps.newHashMap();
static
{
STRATEGY_MAP = STRATEGIES.stream().collect(Collectors.toMap(Strategy::strategy, s -> s));
}
@Override
publicvoidexecute(String strategy){
STRATEGY_MAP.get(strategy).algorithm();
}
}
STRATEGIES
列表來儲存所有Strategy實現類的例項,以及一個叫做STRATEGY_MAP
的Map來儲存strategy和Strategy例項之間的對應關係,static塊中的程式碼用於從STRATEGIES
列表構造STRATEGY_MAP
。這樣,在execute方法中就可以很方便地獲取到指定strategy的Strategy例項。實現並運用策略模式
@Component
publicclassConcreteStrategyAimplementsStrategy{
@Override
publicStringstrategy(){
returnStrategySelector.strategyA.getStrategy();
}
@Override
publicvoidalgorithm(){
System.out.println(
"process with strategyA..."
);
}
}
@Component
publicclassConcreteStrategyBimplementsStrategy{
@Override
publicStringstrategy(){
returnStrategySelector.strategyB.getStrategy();
}
@Override
publicvoidalgorithm(){
System.out.println(
"process with strategyB..."
);
}
}
@Component
publicclassConcreteStrategyCimplementsStrategy{
@Override
publicStringstrategy(){
returnStrategySelector.strategyC.getStrategy();
}
@Override
publicvoidalgorithm(){
System.out.println(
"process with strategyC..."
);
}
}
@Configuration
publicclassStrategyConfig{
@Bean
publicStrategyRunnerrunner(List<Strategy> strategies){
Map<String,Strategy> strategyMap = strategies.stream().collect(Collectors.toMap(Strategy::strategy, s -> s));
return
flag -> strategyMap.get(flag).algorithm();
}
}
List<Strategy>
來構造一個Map<String, Strategy>
。只不過,這裡的strategies列表不是我們自己構造的,而是透過方法引數傳進來的。由於strategyRunner標註了Bean註解,因此引數上的List<Strategy>
實際上是在Spring Boot初始化過程中從容器獲取的,所以我們之前向容器中註冊的那兩個實現類會在這裡被注入。@Autowiredprivate
StrategyRunner strategyRunner;
@RestController
@RequestMapping
(value =
"/designPatterns"
)
publicclassDesignPatternController{
@Autowired
privateStrategyRunner strategyRunner;
@GetMapping
(value =
"/algorithm"
)
publicvoidalgorithm(
@RequestParam
(
"strategy"
) String strategy){
strategyRunner.execute(strategy);
}
}
process with strategyA...
3.2 簡單工廠模式
3.2.1 定義一個策略類:
public
interfaceIPayment{
/**
* 支付
*
*
@param
paymentBody
*/
Booleanpay(PaymentBody paymentBody);
}
publicclassAliPayimplementsIPayment{
@Override
publicBooleanpay(PaymentBody paymentBody){
System.out.println(
"支付寶支付..."
);
returnBoolean.TRUE;
}
}
publicclassWechatPayimplementsIPayment{
@Override
publicBooleanpay(PaymentBody paymentBody){
System.out.println(
"微信支付..."
);
returnBoolean.TRUE;
}
}
publicclassUnionPayimplementsIPayment{
@Override
publicBooleanpay(PaymentBody paymentBody){
System.out.println(
"銀聯支付..."
);
returnBoolean.TRUE;
}
}
3.2.2 建立策略工廠
package
com.universal.core.designPatterns.factory;
import
cn.hutool.core.util.EnumUtil;
import
cn.hutool.core.util.ReflectUtil;
import
com.universal.core.designPatterns.enums.PayStrategyEnum;
import
org.springframework.stereotype.Component;
/**
* Factory for payment methods
*/
@Component
publicclassPaymentFactory{
publicstaticIPaymentgetPayStrategy(String type){
// 1.透過列舉中的type獲取對應的value
Stringvalue=EnumUtil.getFieldBy(PayStrategyEnum::getValue,PayStrategyEnum::getType, type);
// 2.使用反射機制建立對應的策略類
IPaymentpayment=ReflectUtil.newInstance(value);
return
payment;
}
}
3.3.3 定義策略列舉
/**
* 支付策略列舉
*/
@Getter
publicenumPayStrategyEnum{
ZFB(
"ZFB"
,
"com.universal.core.designPatterns.factory.impl.AliPay"
),
WX(
"WX"
,
"com.universal.core.designPatterns.factory.impl.WechatPay"
),
UNION(
"UNION"
,
"com.universal.core.designPatterns.factory.impl.UnionPay"
);
String type;
String value;
PayStrategyEnum(String type,String value){
this
.type = type;
this
.value = value;
}
}
3.3.4 建立策略的上下文角色
@Data
publicclassPaymentContext{
@Resource
privateIPayment paymentStrategy;
publicPaymentContext(IPayment paymentStrategy){
this
.paymentStrategy = paymentStrategy;
}
publicBooleanpay(PaymentBody paymentBody){
returnthis.paymentStrategy.pay(paymentBody);
}
}
3.4.5 提供統一訪問處理入口
package
com.universal.core.designPatterns.factory;
import
cn.hutool.core.util.EnumUtil;
import
com.universal.core.designPatterns.enums.PayStrategyEnum;
import
org.springframework.stereotype.Component;
@Component
publicclassPaymentStrategyHandler{
publicstaticBooleanpay(PaymentBody payBody){
if
(!EnumUtil.contains(PayStrategyEnum
.class, payBody.getType()))
{
thrownewIllegalArgumentException(
"不支援的支付方式!"
);
}
// 1.獲取支付策略物件
IPaymentpayStrategy=PaymentFactory.getPayStrategy(payBody.getType());
// 2.獲取支付策略上下文
PaymentContextpaymentContext=newPaymentContext(payStrategy);
// 3.進行支付
return
paymentContext.pay(payBody);
}
}
3.4.6 建立Controller
@RestController
@RequestMapping
(value =
"/designPatterns"
)
publicclassDesignPatternController{
@PostMapping
(
"/pay"
)
publicBooleanpay(
@RequestBody
PaymentBody paymentBody){
returnPaymentStrategyHandler.pay(paymentBody);
}
}
3.3 單例模式
//懶漢式(靜態內部類)
classSingleton{
privateSingleton(){}
//寫一個靜態內部類,該類中有一個靜態屬性Singleton
privatestaticclassSingletonInstance{
privatestaticfinalSingletonINSTANCE=newSingleton();
}
publicstaticsynchronizedSingletongetInstance(){
returnSingletonInstance.INSTANCE;
}
}
3.4 代理模式
代理模式Proxy, 為其他物件提供一種代理以控制對這個物件的訪問。

/**
* 活動類,目的是出租房子
*/
publicinterfaceSubject
{
/**
* 租房介面
*/
voidrentHouse()
;
}
/**
* 房東
*/
publicclassHouseOwnerimplementsSubject{
/**
* 實現租房方法
*/
@Override
publicvoidrentHouse(){
System.out.println(
"房東成功出租了房子..."
);
}
}
/**
* 中介代理類
*
* 一般情況下我們不能直接聯絡到房東,所以需要提供一個代理類,即中介類
*/
publicclassHouseProxyimplementsSubject{
privateHouseOwnerhouseOwner=newHouseOwner();
@Override
publicvoidrentHouse(){
System.out.println(
"中介收取代理費,幫助房東出租房子..."
);
houseOwner.rentHouse();
}
}

3.5 工廠方法模式
工廠方法模式(Factory Method),定義一個用於建立物件的介面,讓子類決定例項化哪一個類,工廠方法是一個類的例項化延遲到其子類,通俗來說:它提供了一種例項化邏輯委託子類的方法。
NetworkConfigFactoryService
工廠類package
com.universal.core.designPatterns.factoryMethod.factory;
import
com.universal.core.designPatterns.factoryMethod.NetworkConfigCrudService;
publicinterfaceNetworkConfigFactoryService
{
/**
* 獲取指定的處理邏輯類
*
*
@param
productType
*
@return
*/
NetworkConfigCrudService getSpecificService(String productType)
;
}
NetworkConfigFactoryService
工廠實現類@Service
publicclassNetworkConfigFactoryServiceImplimplementsNetworkConfigFactoryService{
privatefinalAServiceImpl aService;
privatefinalBServiceImpl bService;
privatefinalCServiceImpl cService;
privatefinalDServiceImpl dService;
@Override
publicNetworkConfigCrudServicegetSpecificService(String productType){
NetworkConfigCrudServicenetworkConfigCrudService=
null
;
switch
(productType){
case"A"
:
networkConfigCrudService = aService;
break
;
case"B"
:
networkConfigCrudService = bService;
break
;
case"C"
:
networkConfigCrudService = cService;
break
;
case"D"
:
networkConfigCrudService = dService;
break
;
}
return
networkConfigCrudService;
}
}
NetworkConfigCrudService
publicinterfaceNetworkConfigCrudService
{
NetworkConfigVO getNetwork(NetworkConfigDTO networkConfigDTO)
;
}
AServiceImpl
、BServiceImpl
、CServiceImpl
、DServiceImpl
,分別對應不同的邏輯:
@Service
publicclassAServiceImplimplementsNetworkConfigCrudService{
@Override
publicNetworkConfigVOgetNetwork(NetworkConfigDTO networkConfigDTO){
returnnewNetworkConfigVO();
}
}
@Service
publicclassBServiceImplimplementsNetworkConfigCrudService{
@Override
publicNetworkConfigVOgetNetwork(NetworkConfigDTO networkConfigDTO){
returnnewNetworkConfigVO();
}
}
@Service
publicclassCServiceImplimplementsNetworkConfigCrudService{
@Override
publicNetworkConfigVOgetNetwork(NetworkConfigDTO networkConfigDTO){
returnnewNetworkConfigVO();
}
}
@Service
publicclassDServiceImplimplementsNetworkConfigCrudService{
@Override
publicNetworkConfigVOgetNetwork(NetworkConfigDTO networkConfigDTO){
returnnewNetworkConfigVO();
}
}
@RestController
@Slf
4j
@RequestMapping
(value =
"/networkConfig"
)
publicclassNetworkConfigController{
privatefinalNetworkConfigFactoryService factoryService;
@PostMapping
(value =
"/getNetworkDetails"
, produces = MediaType.APPLICATION_JSON_VALUE)
publicApiResult<NetworkConfigVO>getNetworkDetails(
@RequestBody
NetworkConfigDTO networkConfigDTO){
//獲取AService處理類邏輯
NetworkConfigCrudServiceaService= factoryService.getSpecificService(
"A"
);
NetworkConfigVOnetwork= aService.getNetwork(networkConfigDTO);
returnApiResult.success(network);
}
}
3.6 觀察者模式
初識觀察者模式:報社+訂閱者 = 觀察者模式。
要點
-
觀察者模式定義了物件之間一對多的關係。 -
主題(可觀察者)用一個共同的介面來更新觀察者。 -
觀察者和可觀察者之間用松耦合方式結合,可觀察者不知道觀察者的細節,只知道觀察者實現了觀察者介面。 -
使用次模式時,你可以從被觀察者處推或拉資料(推的方式被認為是更正確的)。 -
有多個觀察者時,不可以依賴特定的通知次序。 -
java中有多種觀察者模式的實現,包括了通用的 java.util.Observable
,不過需要注意Observable實現上所帶來的問題,有必要的話,可以實現自己的Observable。 -
Spring也大量使用觀察者模,比如ListenrEvent訊息訂閱與釋出;
案例
氣象監測應用的物件分析
-
氣象站(獲取實際氣象資料的物理裝置) -
WeatherData物件(最總來自氣象站的資料,並更新佈告板) -
佈告板(顯示目前天氣狀況給使用者看)。
實現氣象站
//主題介面
interfaceSubject{
//註冊觀察者
publicvoidregisterObserver(Observer o);
//刪除觀察者
publicvoidremoveObserver(Observer o);
//當主題狀態改變時,這個方法會被呼叫,以通知所有的觀察者
publicvoidnotifyObserver();
}
interfaceObserver{
//當氣象觀測值改變時,主題會把這些狀態值當作方法的引數,傳送給觀察者
publicvoidupdate(
float
temp,
float
humidity,
float
pressure);
}
interfaceDisplay{
//當佈告板需要顯示時,呼叫此方法
publicvoiddisplay();
}
classWeatherDataimplementsSubject
{
privateArrayList<Observer> observers;
privatefloat temperature;
privatefloat humidity;
privatefloat pressure;
publicWeatherData(){
observers=newArrayList<Observer>();
}
@Override
publicvoidregisterObserver(Observer o){
observers.add(o);
}
@Override
publicvoidremoveObserver(Observer o){
int
i=observers.indexOf(o);
if
(i>=
0
){
observers.remove(i);
}
}
@Override
publicvoidnotifyObserver(){
for
(Observer observer:observers){
observer.update(temperature,humidity,pressure);
}
}
//當從氣象站得到更新觀測值時,我們通知觀察者
publicvoidmeasurementsChanged(){
notifyObserver();
}
publicvoidsetMeasurements(
float
temperature,
float
humidity,
float
pressure){
this
.temperature=temperature;
this
.humidity=humidity;
this
.pressure=pressure;
measurementsChanged();
}
//WeatherData的其他方法
}
建立佈告板
classCurrentConditionDisplayimplementsObserver,DisplayElement
{
// 溫度
privatefloat temperature;
// 溼度
privatefloat humidity;
// 氣壓
privatefloat pressure;
privateSubject weatherData;
publicCurrentConditionDisplay(Subject weatherData){
this
.weatherData=weatherData;
weatherData.registerObserver(
this
);
}
@Override
publicvoiddisplay(){
System.out.println(
"這裡氣象臺更新的天氣資料..."
);
}
@Override
publicvoidupdate(
float
temp,
float
humidity,
float
pressure){
this
.temperature = temp;
this
.humidity = humidity;
this
.pressure =
pressure
display()
;
}
}
classWeatherDataTWOextendsObservable
{
privatefloat temperature;
privatefloat humidity;
privatefloat pressure;
publicWeatherDataTWO(){
}
publicvoidmeasurementsChanged(){
//在呼叫notifyObservers()之前,要先呼叫setChanged()來指示狀態已經改變
setChanged();
//我們沒有呼叫notifyObservers傳送資料物件,表示我們採用的做法是拉。
notifyObservers();
}
publicvoidsetMeasurements(
float
temperature,
float
humidity,
float
pressure){
this
.temperature=temperature;
this
.humidity=humidity;
this
.pressure=pressure;
measurementsChanged();
}
publicfloatgetTemperature(){
return
temperature;
}
publicfloatgetHumidity(){
return
humidity;
}
publicfloatgetPressure(){
return
pressure;
}
}
classCurrentConditionsDisplayimplementsjava.util.Observer,DisplayElement
{
Observable observable;
privatefloat temperature;
privatefloat humidity;
publicCurrentConditionsDisplay(Observable observable){
this
.observable=observable;
observable.addObserver(
this
);
}
@Override
publicvoiddisplay(){
System.out.println(
"這裡氣象臺更新的天氣資料..."
);
}
@Override
publicvoidupdate(Observable o, Object arg){
if
(o instanceofWeatherDataTWO){
WeatherDataTWO weatherDataTWO=(WeatherDataTWO) o;
this
.temperature=weatherDataTWO.getTemperature();
this
.humidity=weatherDataTWO.getHumidity();
display();
}
}
}
3.7 模板方法模式
模板方法(Template Method) 是一種行為設計模式。模板方法設計模式用於建立方法存根並將某些實現步驟推遲到子類。
模板方法抽象類
public
abstractclassHouseTemplate{
/**
* buildHouse()是模板方法,定義個執行幾個步驟的執行順序
*
* template method, final so subclasses can't override final修飾,子類不能重寫
*/
publicfinalvoidbuildHouse(){
//建造地基
buildFoundation();
//建造柱子
buildPillars();
//建造牆壁
buildWalls();
//建造窗戶
buildWindows();
System.out.println(
"House is built successfully"
);
}
privatevoidbuildFoundation(){
System.out.println(
"Building foundation with cement, iron rods and sand"
);
}
/**
* methods to be implemented by subclasses
*/
publicabstractvoidbuildPillars();
publicabstractvoidbuildWalls();
/**
* default implementation
*/
privatevoidbuildWindows(){
System.out.println(
"Building Glass Windows"
);
}
}
package
com.universal.core.designPatterns.templateMethod;
/**
* 木房
*/
publicclassWoodenHouseextendsHouseTemplate{
@Override
publicvoidbuildPillars(){
System.out.println(
"Building Pillars With Wood coating..."
);
}
@Override
publicvoidbuildWalls(){
System.out.println(
"Building Wooden Walls..."
);
}
}
package
com.universal.core.designPatterns.templateMethod;
/**
* 玻璃房
*/
publicclassGlassHouseextendsHouseTemplate{
@Override
publicvoidbuildPillars(){
System.out.println(
"Building Pillars With Glass coating..."
);
}
@Override
publicvoidbuildWalls(){
System.out.println(
"Building Glass Walls..."
);
}
}
package
com.universal.core.designPatterns.templateMethod;
/**
* 混泥土房屋
*/
publicclassConcreteHouseextendsHouseTemplate{
@Override
publicvoidbuildPillars(){
System.out.println(
"Building Pillars With Concrete coating..."
);
}
@Override
publicvoidbuildWalls(){
System.out.println(
"Building Concrete Walls..."
);
}
}
package
com.universal.core.designPatterns.templateMethod;
publicclassHousingClient{
publicstaticvoidmain(String[] args){
HouseTemplatehouseBuilder=newWoodenHouse();
houseBuilder.buildHouse();
System.out.println(
"--------------"
);
houseBuilder =newGlassHouse();
houseBuilder.buildHouse();
System.out.println(
"--------------"
);
houseBuilder =newConcreteHouse();
houseBuilder.buildHouse();
}
}
Building foundation with cement,iron rods and sand
BuildingPillarsWithWood coating...
BuildingWoodenWalls...
BuildingGlassWindows
Houseis built successfully
--------------
Building foundation with cement,iron rods and sand
BuildingPillarsWithGlass coating...
BuildingGlassWalls...
BuildingGlassWindows
Houseis built successfully
--------------
Building foundation with cement,iron rods and sand
BuildingPillarsWithConcrete coating...
BuildingConcreteWalls...
BuildingGlassWindows
Houseis built successfully
Process finished withexit code
0
3.8 介面卡模式
介面卡模式Adapter 是將一個介面轉換成另一個客戶所期望的介面。Adapter 介面卡讓那些本來因為介面不相容的類可以合作無間。
-
目標介面(Traget):客戶期待的介面,目標可以是具體的或者抽象的類,也可以是介面。 -
需要適配的物件(Source Adaptee):需要適配的物件。 -
介面卡(Adapter):透過包裝一個需要適配的物件,把原介面轉成目標介面。

//要適配的類:網線
publicclassAdaptee
{
//功能:上網
publicvoidrequest()
{
System.out.println(
"連結網線上網"
);
}
}
//介面轉換器的抽象實現
publicinterfaceNetToUsb
{
//作用:處理請求,網線 => usb
publicvoidhandleRequest()
;
}
//真正的介面卡,餘姚連結usb,連線網線
publicclassAdapterextendsAdapteeimplementsNetToUsb{
@Override
publicvoidhandleRequest(){
//可以上網了
super
.request();
}
}
//客戶端類:想上網,插不上網線
publicclassComputer{
//電腦需要連線上轉接器才可以上網
publicvoidnet(NetToUsb adapter){
//上網的具體實現:找一個轉接頭
adapter.handleRequest();
}
publicstaticvoidmain(String[] args){
//電腦,介面卡,網線
Computercomputer=newComputer();
//電腦
Adapteradapter=newAdapter();
//轉接器
computer.net(adapter);
//電腦直接連線轉接器就可以
}
}
-
java.util.Arrays#asList()open in new window
-
java.util.Collections#list()open in new window
-
java.util.Collections#enumeration()open in new window
-
javax.xml.bind.annotation.adapters.XMLAdapter
四、總結





