開(kāi)放封閉原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
定義:軟件實(shí)體(類(lèi)、模塊、函數(shù)等)應(yīng)該是可以擴(kuò)展的,但是不可修改。對(duì)于擴(kuò)展是開(kāi)放的,對(duì)于更改是封閉的。關(guān)鍵是抽象,將一個(gè)功能的通用部分和實(shí)現(xiàn)細(xì)節(jié)部分清晰的分離開(kāi)來(lái)。
這里要求我們寫(xiě)代碼要有抽象的概念。什么是抽象?指由實(shí)體抽離出概念的思考過(guò)程。就是從眾多的對(duì)象中抽離出共同的本質(zhì)的特征。在寫(xiě)代碼的過(guò)程中,需要抽象類(lèi)的地方,只需要抓住這個(gè)類(lèi)的本質(zhì)功能,不要老想著它在這個(gè)工程中的具體功能。
我們繼續(xù)看開(kāi)放封閉原則,這個(gè)原則要求,將一個(gè)功能的共用部分和實(shí)現(xiàn)部分清晰地分離開(kāi)來(lái)。因?yàn)樵谧畛醮罱軜?gòu)的時(shí)候你不能預(yù)測(cè)到所有將要發(fā)生的變化,那么這個(gè)類(lèi)也就不是一塵不變的,隨著在各個(gè)模塊中具體實(shí)現(xiàn)的時(shí)候,你發(fā)現(xiàn)抽象的類(lèi)適合這個(gè)功能,但是對(duì)另一個(gè)功能又不適合。那么是否要返回去修改抽象類(lèi)呢?這個(gè)代價(jià)是很大的,需要重新全盤(pán)思考,還要調(diào)整具體細(xì)節(jié)。如果程序還沒(méi)發(fā)布還好一些,一旦程序發(fā)布了,那么返回修改抽象類(lèi),影響將更大。所以在開(kāi)始抽象的時(shí)候就要防止這樣的現(xiàn)象發(fā)生,要遵循開(kāi)放封閉原則。抽象類(lèi)、接口是一種標(biāo)準(zhǔn),在程序中一旦定義好,就不能輕易去修改,需求有變化,怎么辦呢?可以擴(kuò)展這個(gè)接口,重寫(xiě)方法,或者繼承后增加新的方法,但是一定不要去修改。
下面用兩個(gè)例子來(lái)說(shuō)明開(kāi)放封閉原則。
1、連接數(shù)據(jù)庫(kù)為例。
比如在程序中用到的不同類(lèi)型的數(shù)據(jù)庫(kù)連接,Access和Oracle。直接連接如下:
class ConnectAccess { public string ConnectString() { string dataPath = "數(shù)據(jù)庫(kù)路徑"; return string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Persist Security Info=True;Jet OLEDB:Database Password={1}", dataPath, "密碼"); } } class ConnectOracle { public string ConnectString() { return @"server=localhost;database=命名空間;uid=用戶(hù)名;pwd=密碼"; } }
調(diào)用
static void Main(string[] args) { //連接Access ConnectAccess connAccess = new ConnectAccess(); OleDbConnection accessConnection = new OleDbConnection(connAccessConnectString()); //連接Oracle ConnectOracle connOracle = new ConnectOracle(); OracleConnection oracleConnection = new OracleConnection(connOracleConnectString()); }
這樣每次都要去考慮OleDbConnection的參數(shù)到底用哪個(gè)。下面修改一下。抽象一個(gè)接口。
interface ConnectDataBase { string ConnectString(); } class ConnectAccess : ConnectDataBase { #region ConnectDataBase 成員 public string ConnectString() { string dataPath = "數(shù)據(jù)庫(kù)路徑"; return stringFormat("Provider=MicrosoftJetOLEDB0;Data Source={0};Persist Security Info=True;Jet OLEDB:Database Password={1}", dataPath, "密碼"); } #endregion } class ConnectOracle : ConnectDataBase { #region ConnectDataBase 成員 public string ConnectString() { return @"server=localhost;database=命名空間;uid=用戶(hù)名;pwd=密碼"; } #endregion }
調(diào)用
static void Main(string[] args) { ConnectDataBase conn = null; //連接Access conn = new ConnectAccess(); OleDbConnection accessConnection = new OleDbConnection(connConnectString()); //連接Oracle conn = new ConnectOracle(); OracleConnection oracleConnection = new OracleConnection(connConnectString()); }
改過(guò)后,只需關(guān)心conn用哪一個(gè)類(lèi)實(shí)例化,就可以了。不過(guò)大家可能看到,由于Oracle的連接必須OracleConnection,可能優(yōu)勢(shì)不容易看出來(lái)。
2、基本類(lèi)型作為方法參數(shù)為例。
一般的設(shè)計(jì)原則之所以強(qiáng)調(diào)方法參數(shù)盡量避免基本類(lèi)型,原因正在于此。比較如下兩個(gè)方法定義:
//定義1 bool Connect(string userName, string password, string wifiAddress, int port) { return false; }
//定義2 bool Connect(Account account) { return false; }
public class Account { public string UserName { get; set; } public string Password { get; set; } public string WifiAddress { get; set; } public int Port { get; set; } }
相比較而言,定義2多了一個(gè)Account類(lèi)的定義,Connect()方法明顯更加穩(wěn)定。如果Connect()方法wifiAddress發(fā)生改變,定義1必須修改該方法的接口,對(duì)應(yīng)的,所有調(diào)用Connect()方法的對(duì)象都會(huì)受到影響;而定義2只需要修改Account類(lèi),由于Connect()方法的接口保持不變,而對(duì)于Connect()方法的調(diào)用者并不需wifiAddress,這樣的修改就完全不會(huì)影響調(diào)用者,從而降低需求變化帶來(lái)的影響。
總之開(kāi)放封閉原則最關(guān)鍵的是抽象,但是也并不是說(shuō)一旦抽象接口、類(lèi)確定就一定不能修改。只是,我們?cè)诔橄蟮臅r(shí)候就要全面思考,爭(zhēng)取做到不用修改,一旦需求有變化,只需在實(shí)現(xiàn)的時(shí)候有變動(dòng)。當(dāng)然,需求是千變?nèi)f化的,一旦需要改動(dòng)抽象的部分,那么只要前面嚴(yán)格遵循了該原則,影響也會(huì)小得多。當(dāng)然了如果修改了,一定要進(jìn)行單元測(cè)試,凡是用到的地方都要測(cè)試正確。
- Java設(shè)計(jì)模式常用原則解析
- 單一職責(zé)原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- 高內(nèi)聚低耦合原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- 合成聚合復(fù)用原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- ocp開(kāi)閉原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Java中的設(shè)計(jì)模式與7大原則歸納整理
- 淺談Java設(shè)計(jì)模式之開(kāi)放封閉原則
- 簡(jiǎn)單講解Java設(shè)計(jì)模式編程中的單一職責(zé)原則
- 理解Java設(shè)計(jì)模式編程中的迪米特原則
- 詳解java設(shè)計(jì)模式之六大原則
相關(guān)文章
Spring如何使用PropertyPlaceholderConfigurer讀取文件
這篇文章主要介紹了Spring如何使用PropertyPlaceholderConfigurer讀取文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12java中實(shí)體類(lèi)實(shí)現(xiàn)時(shí)間日期自動(dòng)轉(zhuǎn)換方式
這篇文章主要介紹了java中實(shí)體類(lèi)實(shí)現(xiàn)時(shí)間日期自動(dòng)轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06關(guān)于JpaRepository的關(guān)聯(lián)查詢(xún)和@Query查詢(xún)
這篇文章主要介紹了JpaRepository的關(guān)聯(lián)查詢(xún)和@Query查詢(xún),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11IDEA中實(shí)體類(lèi)(POJO)與JSON快速互轉(zhuǎn)問(wèn)題
這篇文章主要介紹了IDEA中實(shí)體類(lèi)(POJO)與JSON快速互轉(zhuǎn),本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08Java內(nèi)部類(lèi)原理、概述與用法實(shí)例詳解
這篇文章主要介紹了Java內(nèi)部類(lèi)原理、概述與用法,結(jié)合實(shí)例形式詳細(xì)分析了Java內(nèi)部類(lèi)的相關(guān)概念、原理、訪問(wèn)、調(diào)用方法等操作技巧與注意事項(xiàng),需要的朋友可以參考下2019-03-03SpringMVC 方法四種類(lèi)型返回值總結(jié)(你用過(guò)幾種)
這篇文章主要介紹了SpringMVC 方法四種類(lèi)型返回值總結(jié)(你用過(guò)幾種),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05