如何優雅的將設計模式運用到實際專案中去?

👉 這是一個或許對你有用的社群
🐱 一對一交流/面試小冊/簡歷最佳化/求職解惑,歡迎加入芋道快速開發平臺知識星球。下面是星球提供的部分資料:
👉這是一個或許對你有用的開源專案
國產 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 雙版本 

一、🌈設計模式介紹

所謂 “設計模式”,就是一套反覆被人使用或驗證過的方法論。從抽象或者更宏觀的角度上看,只要符合使用場景並且能解決實際問題,模式應該既可以應用在DDD中,也可以應用在設計模式中。
基於 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/

三、設計模式簡單實現模板

場景: 商場搞活動,根據客戶購買商品的金額,收費時給與不同的打折,比如,購買 金額>=2000 的打八折(0.8),金額 500 ~ 1000 的,打九折(0.9),購買金額 0 ~ 500 的九五折(0.95),根據不同的金額走不同計算策略邏輯。

3.1 策略模式

首先定義一個Strategy介面來表示一個策略:
public

 interfaceStrategy{

/**

     * 採用策略

     */

Stringstrategy();

/**

     * 計算方法邏輯

     */

voidalgorithm();

}

其中strategy方法返回當前策略的唯一標識,algorithm則是該策略的具體執行的計算邏輯。
下面是Strategy介面的兩個實現類:
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..."

);

}

}

自定義策略選擇列舉 StrategySelector:
@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;

}

}

然後定義一個StrategyRunner介面用來表示策略的排程器:
publicinterfaceStrategyRunner

{

voidexecute(String strategy)

;

}

execute方法內部透過判斷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();

}

}

在StrategyRunnerImpl內部,定義了一個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..."

);

}

}

然後,定義一個StrategyConfig配置類,用於向容器注入一個StrategyRunner:
@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();

}

}

不難發現,strategyRunner方法的實現,其中的邏輯與之前的StrategyRunnerImpl幾乎完全相同,也是根據一個List<Strategy>來構造一個Map<String, Strategy>。只不過,這裡的strategies列表不是我們自己構造的,而是透過方法引數傳進來的。由於strategyRunner標註了Bean註解,因此引數上的List<Strategy>實際上是在Spring Boot初始化過程中從容器獲取的,所以我們之前向容器中註冊的那兩個實現類會在這裡被注入。
這樣,我們再也無需操心繫統中一共有多少個Strategy實現類,因為Spring Boot的自動配置會幫我們自動發現所有實現類。我們只需編寫自己的Strategy實現類,然後將它註冊進容器,並在任何需要的地方注入StrategyRunner:
@Autowiredprivate

 StrategyRunner 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 簡單工廠模式

舉個場景例子🌰:
使用者支付場景,目前支援支付寶支付和微信支付,未來會新增銀行卡,雲閃付等方式。使用策略模式,每一種支付方式都是一種策略,根據使用者傳入的支付型別,建立不同的策略類,使用工廠模式,透過封裝一個PaymentStrategyHandler策略處理類,其他系統直接透過一個統一的入口,進行該功能的呼叫,使用門面模式。
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

.classpayBody.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, 為其他物件提供一種代理以控制對這個物件的訪問。
代理模式 實際上在平時中也運用的非常廣泛,最經典的例子就是房東委託中介代理出租房子的案例,本文也是採用這個案例對代理模式進行解釋和程式碼實現。
程式碼例項🌰:
建立一個Subject類:

/**

 * 活動類,目的是出租房子

 */


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)

;

}

它的實現類分別是 AServiceImplBServiceImplCServiceImplDServiceImpl,分別對應不同的邏輯:
@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();

}

}

控制層NetworkConfigController
@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 觀察者模式

觀察者模式Observer 定義了物件之間的一對多依賴,當一個物件改變狀態時,它的所有依賴者都會收到通知並自動更新。
初識觀察者模式:報社+訂閱者 = 觀察者模式。
要點
  • 觀察者模式定義了物件之間一對多的關係。
  • 主題(可觀察者)用一個共同的介面來更新觀察者。
  • 觀察者和可觀察者之間用松耦合方式結合,可觀察者不知道觀察者的細節,只知道觀察者實現了觀察者介面。
  • 使用次模式時,你可以從被觀察者處推或拉資料(推的方式被認為是更正確的)。
  • 有多個觀察者時,不可以依賴特定的通知次序。
  • java中有多種觀察者模式的實現,包括了通用的java.util.Observable,不過需要注意Observable實現上所帶來的問題,有必要的話,可以實現自己的Observable。
  • Spring也大量使用觀察者模,比如ListenrEvent訊息訂閱與釋出;
案例
直接以氣象站為例,其中天氣資訊就表示被觀察者,天氣佈告板就表示訂閱者和觀察者,當天氣發生變化(被觀察者)時,會透過notifyObserver通知所有觀察者,並呼叫他們的控制方法處理資料。
一個WeatherData物件負責追蹤目前的天氣狀況(溫度,溼度,氣壓)。我們希望你們能建立一個應用,有三種佈告板,分別顯示目前的狀況、氣象統計及簡單的預報。當WeatherObject物件獲得最新的測量資料時,三種佈告板必須即時更新。
氣象監測應用的物件分析
此係統中的三個部分是:
  • 氣象站(獲取實際氣象資料的物理裝置)
  • WeatherData物件(最總來自氣象站的資料,並更新佈告板)
  • 佈告板(顯示目前天氣狀況給使用者看)。
實現氣象站
//主題介面

interfaceSubject{

//註冊觀察者

publicvoidregisterObserver(Observer o);

//刪除觀察者

publicvoidremoveObserver(Observer o);

//當主題狀態改變時,這個方法會被呼叫,以通知所有的觀察者

publicvoidnotifyObserver();

}
interfaceObserver{

//當氣象觀測值改變時,主題會把這些狀態值當作方法的引數,傳送給觀察者

publicvoidupdate(

float

 temp,

float

 humidity,

float

 pressure);

}
interfaceDisplay{

//當佈告板需要顯示時,呼叫此方法

publicvoiddisplay();

}

在WeatherData中實現主題介面
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()

;

}

}

利用內建的支援重寫WeatherData
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) 是一種行為設計模式。模板方法設計模式用於建立方法存根並將某些實現步驟推遲到子類。
模板方法定義了執行演算法的步驟,它可以提供可能對所有或者部分子類通用的預設實現,下面透過一個簡單的例子來理解這個模式,假設我們想提供一種演算法了該房子,建造房屋需要執行的步驟是:建造地基->建造支柱->建造牆壁和窗戶。
重點的一點是我們不能改變執行的順序,因為我們不能在構建基礎之前構建視窗,所以在這種情況下,我們可以建立一個模板方法,它將使用不同的方法來建造房子,現在蓋房子的地基對於所有型別的房子都是一樣的,無論是木房、玻璃房子還是混泥土房。
所以我們可以為此提供基礎實現,如果子類想要覆蓋這個方法,他們可以自己選擇,但是大多數情況下,所有型別的房屋都很常見。為了確保子類不覆蓋模板方法,我們應該將其設為最終方法。
模板方法抽象類
由於我們希望某些方法由子類實現,因此我們必須將我們的基類設為抽象類。
定義抽象類HouseTemplate
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"

);

}

}

WoodenHouse
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..."

);

}

}

GlassHouse
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..."

);
}

}

ConcreteHouse
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..."

);
}

}

HousingClient
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):透過包裝一個需要適配的物件,把原介面轉成目標介面。
舉個例子🌰:我們以網線上網為例,現在有一根水晶頭網線,但是它的介面與電腦的不匹配(因為電腦的是usb或者typec),那麼就需要一個轉接頭,也就是我們說的介面卡,才能夠上網,下面的轉接頭可以理解為介面卡:
類介面卡
首先我們擁有一根網線, 他有上網的功能,但是它的介面與電腦不匹配:
//要適配的類:網線
publicclassAdaptee

{

//功能:上網
publicvoidrequest()

{

        System.out.println(

"連結網線上網"

);

    }

}

因此我們定義了一個usb介面,也就是上面提到的目標介面(Target):
//介面轉換器的抽象實現
publicinterfaceNetToUsb

{

//作用:處理請求,網線 => usb
publicvoidhandleRequest()

;

}

定義一個介面卡繼承著網線,連線著usb介面:
//真正的介面卡,餘姚連結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

四、總結

設計模式(Design pattern) 代表了最佳的實踐,通常被有經驗的面向物件的軟體開發人員所採用。設計模式是軟體開發人員在軟體開發過程中面臨的一般問題的解決方案。
這些解決方案是眾多軟體開發人員經過相當長的一段時間的試驗和錯誤總結出來的。對於一個進階高階開發的技術人員來說,瞭解設計模式的理念和具體的實現頗為重要,本期內容分享就到這裡了,如果感覺對你有幫助的,歡迎點贊👍+評論💬+收藏❤

歡迎加入我的知識星球,全面提升技術能力。
👉 加入方式,長按”或“掃描”下方二維碼噢
星球的內容包括:專案實戰、面試招聘、原始碼解析、學習路線。
文章有幫助的話,在看,轉發吧。
謝謝支援喲 (*^__^*)

相關文章