當接口要加入新方法時,我后悔沒有早點學設計模式了

📢?聲明:
🍄 大家好,我是風箏
🌍 作者主頁:【古時的風箏CSDN主頁】。
?? 本文目的為個人學習記錄及知識分享。如果有什么不正確、不嚴謹的地方請及時指正,不勝感激。
直達博主:「古時的風箏」 。(搜索或點擊掃碼)
————————————————

假設系統中有一個接口,這個接口已經被10個實現類實現了,突然有一天,新的需求來了,其中5個實現類需要實現同一個方法。然后你就在接口中添加了這個方法的定義,想著一切都很完美。

當你在接口和其中5個實現類中加完這個方法后,一編譯。不妙啊,另外那 5 個實現類報錯了,沒實現新加的這個方法。要知道,接口中的方法定義必須要在實現類中實現才行,缺一個都編譯不過。

這時候你耳邊突然響起了開發之初的老前輩跟你說的話:“這幾個實現以后可能差距越來越大,接口中可能會加方法,注意留口子”。

現在咋整

假設之前的接口是這樣的,只有吃飯和喝水兩個方法。

public interface IUser {/*** 吃飯啊*/void eat();/*** 喝水啊*/void drink();
}

現在有 5 個實現類厲害了,要加一個 play() 方法。

既然情況已經這樣了,現在應該怎么處理。

破罐子破摔吧,走你

不管什么接口不接口的了,哪個實現類要加,就直接在那個實現類里加吧,接口還保持之前的樣子不動,仍然只有吃飯和喝水兩個方法,play 方法就直接加到 5 個實現類中。

public class UserOne implements IUser{@Overridepublic void eat() {System.out.println("吃飯");}@Overridepublic void drink() {System.out.println("喝水");}public void play() {System.out.println("玩兒");}
}

雖然可以實現,但是完全背離了當初設計接口的初衷,本來是照著五星級酒店蓋的,結果蓋了一層之后,上面的變茅草屋了。

從此以后,接口是接口,實現類是實現類,基本上也就沒什么關系了。靈活性倒是出來了,以后想在哪個實現類加方法就直接加了。

再加一個接口行不

還是有點兒追求吧,我新加一個接口行不行。之前的接口不動,新建一個接口,這個接口除了包含之前的兩個方法外,再把 play 方法加進去。

這樣一來,把需要實現 play 方法的單獨在弄一個接口出來。就像下面這樣 IUser是之前的接口。IUserExtend接口是新加的,加入了 play() 方法,需要實現 play() 方法的實現類改成實現新的IUserExtend接口,只改幾個實現關系,改動不是很大嘛,心滿意足了。

但是好景不長啊,過了幾天,又要加新方法了,假設是上圖的 UserOneUserNine要增加方法,怎么辦呢?

假如上天再給我一次機會

假如上天再給我一次重來的機會,我會對自己說:“別瞎搞,看看設計模式吧”。

適配器模式

適配器模式可以通過創建一個適配器類,該適配器類實現接口并提供默認實現,然后已有的實現類可以繼承適配器類而不是直接實現接口。這樣,已有的實現類不需要修改,而只需要在需要覆蓋新方法的實現類中實現新方法。

不是要加個 play() 方法嗎,沒問題,直接在接口里加上。

public interface IUser {void eat();void drink();void play();
} 

適配器類很重要,它是一個中間適配層,是一個抽象類。之前不是實現類直接 implements 接口類嗎,而現在適配器類 implements 接口類,而實現類 extends 適配器類。

在適配器類可以給每個方法一個默認實現,當然也可以什么都不干。

public abstract class UserAdapter implements IUser {@Overridepublic void eat() {// 默認實現}@Overridepublic void drink() {// 默認實現}@Overridepublic void play() {// 默認實現}
}
public class UserNine extends UserAdapter {@Overridepublic void eat() {System.out.println("吃飯");}@Overridepublic void drink() {System.out.println("喝水");}@Overridepublic void play() {System.out.println("玩兒");}
}public class UserTen extends UserAdapter {@Overridepublic void eat() {System.out.println("吃飯");}@Overridepublic void drink() {System.out.println("喝水");}
}

調用方式:

IUser userNine = new UserNine();
userNine.eat();
userNine.drink();
userNine.play();IUser userTen = new UserTen();
userTen.eat();
userTen.drink();

這樣一來,接口中隨意加方法,然后在在適配器類中添加對應方法的默認實現,最后在需要實現新方法的實現類中加入對應的個性化實現就好了。

策略模式

策略模式允許根據不同的策略來執行不同的行為。在這種情況下,可以將新方法定義為策略接口,然后為每個需要實現新方法的實現類提供不同的策略。

把接口改成抽象類,這里面 eat() 和 drink() 方法不變,可以什么都不做,實現類里想怎么自定義都可以。

而 play() 這個方法是后來加入的,所以我們重點關注 play() 方法,策略模式里的策略就用在 play() 方法上。

public abstract class AbstractUser {IPlayStrategy playStrategy;public void setPlayStrategy(IPlayStrategy playStrategy){this.playStrategy = playStrategy;}public void play(){playStrategy.play();}public void eat() {// 默認實現}public void drink() {// 默認實現} 
}

IPlayStrategy是策略接口,策略模式是針對行為的模式,玩兒是一種行為,當然了,你可以把之后要添加的方法都當做行為來處理。

我們定一個「玩兒」這個行為的策略接口,之后不管你玩兒什么,怎么玩兒,都可以實現這個 IPlayStrategy接口。

public interface IPlayStrategy {void play();
}

然后現在做兩個實現類,實現兩種玩兒法。

第一個玩兒游戲的實現

public class PlayGameStrategy implements IPlayStrategy{@Overridepublic void play() {System.out.println("玩游戲");}
}

第二個玩兒足球的實現

public class PlayFootballStrategy implements IPlayStrategy{@Overridepublic void play() {System.out.println("玩兒足球");}
}

然后定義 AbstractUser的子類

public class UserOne extends AbstractUser{@Overridepublic void eat() {//自定義實現}@Overridepublic void drink() {//自定義實現}
}

調用方式:

public static void main(String[] args) {AbstractUser userOne = new UserOne();// 玩兒游戲userOne.setPlayStrategy(new PlayGameStrategy());userOne.play();// 玩兒足球userOne.setPlayStrategy(new PlayFootballStrategy());userOne.play();
}

整體的類關系圖大概是這個樣子:

最后

通過適配器模式和策略模式,我們即可以保證具體的實現類實現共同的接口或繼承共同的基類,同時,又能在新增功能(方法)的時候,盡可能的保證設計的清晰。不像之前那種破罐子破摔的方式,接口和實現類幾乎脫離了關系,每個實現類,各玩兒各的。

您的點贊、收藏、評論都是我前進路上的動力
在這里插入圖片描述

推薦閱讀

? 劍走偏鋒,無頭瀏覽器是什么神奇的家伙

? 新項目決定用 JDK 17了

? 5000字,10張圖,完全掌握 MySQL 事務隔離級別

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/213383.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/213383.shtml
英文地址,請注明出處:http://en.pswp.cn/news/213383.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PP材料粘接ABS材料使用UV膠的好處?

跟隨著現階段材料的不斷發展更迭,PP材料應用越來越廣,生產效率要求越來越高,為了加快生產,提高效率,PP材料的粘接上使用UV膠粘接PP(聚丙烯)和ABS(丙烯腈-丁二烯-苯乙烯共聚物&#x…

python Open3D加載obj

pip安裝Open3D python -m pip install open3d示例代碼 import numpy as np import open3d as o3dpath_obj test/assimp-5.2.5/test/models/OBJ/box.objmesh o3d.io.read_triangle_mesh(path_obj, enable_post_processingTrue)print(np.asarray(mesh.vertices))mesh.compute…

Jenkins:持續集成與持續交付的自動化利器

隨著軟件開發行業的快速發展,持續集成(Continuous Integration,簡稱CI)和持續交付(Continuous Delivery,簡稱CD)已經成為了現代軟件開發的重要理念。Jenkins作為一款開源的持續集成和持續交付工…

企業可以利用SD-WAN打破網絡限制,實現高效穩定的應用訪問

在當今數字化時代,我們面臨著越來越多復雜應用和各種類型的數據傳輸。企業需要實時訪問云應用、視頻會議等關鍵應用,不斷增長的訪問流量,導致應用訪問速度變得越來越慢,給工作效率和用戶體驗帶來了很大困擾。 SD-WAN是否能夠解決這…

javaSwing酒店管理

一、介紹 在這篇博客中,我們將介紹一個基于MySQL數據庫、Java編程語言和Swing圖形用戶界面的簡單酒店管理系統。該系統包括了查詢房客信息、查詢房客狀態、修改房客信息、添加房間信息、添加住戶、退房管理、預定管理、退訂管理、入賬管理、出賬管理、修改資料等多…

0009Java程序設計-ssm微信小程序在慢性疾病管理中的應用

文章目錄 **摘要**目錄系統實現開發環境 編程技術交流、源碼分享、模板分享、網課分享 企鵝🐧裙:776871563 摘要 首先,論文一開始便是清楚的論述了小程序的研究內容。其次,剖析系統需求分析,弄明白“做什么”,分析包括業務分析和業務流程的分析以及用例…

極坐標曲線@典型的4種曲線

文章目錄 abstract典型曲線心形線玫瑰線阿基米德螺線伯努利雙扭線 abstract 除了圓和圓錐曲線外,還有許多曲線用極坐標描述會簡單得多 典型曲線 分析下列曲線時,線分析是否含有三角函數(周期性) 利用描點法做出單個周期內的圖形 作圖:可以打開geogebra https://www.geogebr…

記:vite3+vue3+axios前端項目跨域問題解決【前端和服務器nginx配置】

前言:什么是跨域,網上一搜一大把,所以這里直接跳過,直入主題。 處理方式:不通過后端處理跨域,通過前端服務器nginx處理。 1.前端涉及處理跨域的必要配置(開發環境、生產環境)&…

銀行插件導致的Outlook客戶端無法連接服務器問題

問題現象 最近遇到好些同事出現outlook客戶端無法連接服務器的情況,具體現象就是右下角一直顯示【正在嘗試連接…】或者【需要密碼】,點擊【需要密碼】按鈕,輸密碼的彈窗是一個完全空白的頁面。 此時打開word,右上角那里去登錄o…

LeetCode19. Remove Nth Node From End of List

文章目錄 一、題目二、題解 一、題目 Given the head of a linked list, remove the nth node from the end of the list and return its head. Example 1: Input: head [1,2,3,4,5], n 2 Output: [1,2,3,5] Example 2: Input: head [1], n 1 Output: [] Example 3: I…

智能優化算法應用:基于緞藍園丁鳥算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼

智能優化算法應用:基于緞藍園丁鳥算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼 文章目錄 智能優化算法應用:基于緞藍園丁鳥算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼1.無線傳感網絡節點模型2.覆蓋數學模型及分析3.緞藍園丁鳥算法4.實驗參數設定5.算法…

自動數據增廣論文筆記 | AutoAugment: Learning Augmentation Strategies from Data

谷歌大腦出品 paper: https://arxiv.org/abs/1805.09501 這里是個論文的閱讀心得,筆記,不等同論文全部內容 文章目錄 一、摘要1.1 翻譯1.2 筆記 二、(第三部分)自動增強:直接在感興趣的數據集上搜索最佳增強策略2.1 翻譯2.2 筆記 三、(第四部分)實驗與結…

為什么說數字化轉型能幫助企業降本增效?

引言 數字化轉型是當今商業領域中的關鍵議題,它不僅是技術的應用,更是一種戰略性的變革,對企業而言具有重要意義。在這個數字化時代,企業需要不斷適應和采納新技術,以獲得競爭優勢并提高效率。 數字化轉型旨在將傳統業…

匿名內部類 - ( 零基礎學java )

Java-匿名內部類 我們先分析匿名內部類的結構,然后逐一解釋,最后以下羅列的問題都會在下面的內容中一一得到解答 : 匿名內部類到底是什么? 我們為什么要學習匿名內部類 ? 匿名內部類都有怎樣的作用 ? 匿名內部類應用的場景又有哪些 ? 匿名內部類是否有缺陷? 讓我們…

Java (JDK 21) 調用 OpenCV (4.8.0)

Java 調用 OpenCV 一.OpenCV 下載和安裝二.創建 Java Maven 項目三.其他測試 一.OpenCV 下載和安裝 Open CV 官網 可以下載編譯好的包,也可以下載源碼自行編譯 雙擊安裝 opencv-4.8.0-windows.exe 默認為當前目錄 安裝即解壓縮 根據系統位數選擇 將 x64 目錄下 op…

外匯交易到哪開戶?外匯開戶所需流程有哪些?

外匯交易是一種全球性的金融市場活動,參與者可以通過買入或賣出不同國家的貨幣來獲取利潤。在進行外匯交易之前,開設一個外匯交易賬戶是必要的。本文將介紹外匯交易開戶的重要性、選擇外匯交易平臺的因素以及開戶所需的基本流程,幫助讀者更好…

開往渤海的列車:滄港鐵路如何扮演產業帶城市生態共贏的關鍵先生

新時代構建新格局,新格局呼喚新作為。在交通強國戰略背景下,鐵路運輸企業需要如何彰顯“鐵擔當”? 逢山開路、遇水架橋,身處重要地理區位,滄州滄港鐵路有限公司(以下簡稱“滄港鐵路”)不斷搶抓…

并查集帶壓縮路徑的find

目錄 原因: 優化: 原因: 當路徑比較特殊,如圖: 非常深,最底層進行find時,循環找根(或者遞歸找),消耗就比較大。 我們可以進行優化。 優化: &…

【C++】C++異常語法、使用、規范、異常安全及異常的優缺點

1. C異常概念 異常是一種處理錯誤的方式,當一個函數發現自己無法處理的錯誤時就可以拋出異常,讓函數的直接或間接的調用者處理這個錯誤。 throw: 當問題出現時,程序會拋出一個異常。這是通過使用 throw 關鍵字來完成的。catch: 在您想要處理…

給你的Python程序添點Emoji魔法:使用Emoji模塊增添趣味和個性!

當你想給你的Python程序增添一些趣味和個性時,Emoji模塊是一個很有用的工具。Emoji模塊允許你在Python中使用各種表情符號,從笑臉到動物,甚至是食物和天氣等。在本篇博客中,我們將介紹如何在Python中使用Emoji模塊,并展…