开闭原则
個(gè)人博客原文:
開閉原則
設(shè)計(jì)模式六大原則之六:開閉原則。
簡(jiǎn)介
姓名 :開閉原則
英文名 :Open Closed Principle
價(jià)值觀 :老頑童就是我,休想改變我
個(gè)人介紹 :
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.(軟件中的對(duì)象(類,模塊,函數(shù)等等)應(yīng)該對(duì)于擴(kuò)展是開放的,但是對(duì)于修改是封閉的)
(來自維基百科)
停更了三四天了,這幾天比較忙,不僅僅是工作上,更多是精神上。周日突然老胃病又復(fù)發(fā)了,一直疼到凌晨 4,5 點(diǎn)。因?yàn)檫@次疼得蠻厲害的,所以準(zhǔn)備去醫(yī)院看一下醫(yī)生,這時(shí)候才體驗(yàn)到大城市就醫(yī)之苦。周日晚下載了微醫(yī) App (不是做廣告哈),也不知道哪家醫(yī)院好,在深圳兩年半還沒去過醫(yī)院,隨便選個(gè)三甲醫(yī)院:北京大學(xué)深圳醫(yī)院,看了消化內(nèi)科門診的醫(yī)生列表,整整這一周主任醫(yī)生都預(yù)約滿了,頓時(shí)很崩潰,打電話給醫(yī)院預(yù)約,最快只能預(yù)約 17 號(hào),are you kidding?App 上有個(gè) 『立即問診』功能,在線把狀況告訴醫(yī)生,醫(yī)生一天之內(nèi)接診,需要花 60 塊,我就嘗試一下,沒想到第二天醫(yī)生回復(fù)后,說可以下午去醫(yī)院看,他可以臨時(shí)加號(hào)。就這樣跳過了預(yù)約,直接看病,不知道你是否也苦于看病煩,可以嘗試這個(gè)方法,當(dāng)然,如果你有更好的方法,可以留言讓更多的人了解到。
跑題了跑題了,今天是想和大家分享設(shè)計(jì)模式最后一個(gè)原則:開閉原則。這個(gè)原則要求就是允許擴(kuò)展,拒絕修改。既然上面講到看醫(yī)生,那就用一個(gè)跟看病有關(guān)的例子。
故事從這里開始
小明去醫(yī)院看病,醫(yī)生開了阿司匹林藥,小明去了收費(fèi)臺(tái),付了錢,總共 20 塊錢。例子的代碼如下:
public class OcpTest {public static void main(String[] args) {Hospital hospital = new Hospital();IPatient xiaoMing = new Patient("小明");hospital.sellMedicine(xiaoMing);}}class Medicine {private String name;private BigDecimal price;public Medicine(String name, BigDecimal price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public BigDecimal getPrice() {return price;}public void setPrice(BigDecimal price) {this.price = price;} }class Hospital {private Medicine medicine = new Medicine("阿司匹林", new BigDecimal(20));public void sellMedicine(IPatient patient) {BigDecimal money = patient.pay(medicine);System.out.println(patient.getName() + " 花了 " + money.setScale(2, BigDecimal.ROUND_UP) + " 塊錢買了藥:" + medicine.getName());}}interface IPatient {String getName();BigDecimal pay(Medicine medicine); }class Patient implements IPatient{private String name;public Patient(String name) {this.name = name;}@Overridepublic BigDecimal pay(Medicine medicines) {return medicines.getPrice();}@Overridepublic String getName() {return name;}}第二天和朋友聚會(huì)聊起這事,小紅說道:不對(duì)呀,前幾天我在醫(yī)院也拿了阿司匹林藥,才 14 塊錢呢。小花說:奇怪了,我買的是 16 塊錢。小杰回應(yīng):怎么我買的是 18 塊。怎么這藥這么多個(gè)價(jià)格。小明 Google 搜了一下,發(fā)現(xiàn)價(jià)格跟社保有關(guān),幾個(gè)人便發(fā)現(xiàn),原來他們都是“不同人”:小明沒有社保,小紅社保是一檔,小花社保是二擋,小杰社保是三擋。(假設(shè)社保一檔打 7 折,社保二擋打 8 折,社保三擋打 9 折,虛擬的哈)
發(fā)現(xiàn)了這秘密后,作為和 IT 工作相關(guān)的人,便討論起醫(yī)院系統(tǒng)具體實(shí)現(xiàn)是怎么實(shí)現(xiàn)的。小紅說:這很簡(jiǎn)單呢,藥品給不同人提供不同的價(jià)格。代碼如下:
小花說:藥片本身的價(jià)格是不會(huì)變的,只是給不同人不同價(jià)格,所以可以在病人獲取價(jià)錢的時(shí)候去區(qū)分。代碼如下:
class Patient implements IPatient{private String name;private int level;public Patient(String name) {this.name = name;}@Overridepublic BigDecimal pay(Medicine medicines) {if (level == 1) {return medicines.getPrice().multiply(new BigDecimal(0.7));} else if (level == 2) {return medicines.getPrice().multiply(new BigDecimal(0.8));} else if (level == 3) {return medicines.getPrice().multiply(new BigDecimal(0.9));}return medicines.getPrice();}@Overridepublic String getName() {return name;}}小杰陷入了沉思。。。
小明發(fā)話:你們說的方法都可以實(shí)現(xiàn),但是總感覺不對(duì)勁,如果以后有社保四擋,還是要修改原來的代碼,前 2 天設(shè)計(jì)模式老師講的開閉原則忘記了么?里面說要對(duì)擴(kuò)展開放,對(duì)修改封閉。我覺得這個(gè)藥片價(jià)格是因?yàn)槲覀內(nèi)硕兊?#xff0c;那是不是我們可以把沒社保的歸為一類人,一檔社保的也為一類,以此類推。我覺得這樣實(shí)現(xiàn)更好,增加多 3 類病人,分別是一檔社保、二擋社保、三擋社保。代碼如下:
代碼:
OcpTest.java
看了他們的對(duì)話和代碼,是不是能知道哪種方式更好了?對(duì)于小紅來說,她沒理清價(jià)格變化的原因,價(jià)格變化不在于藥片;小花理清了,但是實(shí)現(xiàn)方式差了點(diǎn),以后如果新增了四擋社保,她的實(shí)現(xiàn)要修改原有的代碼,不符合開閉原則;小明的方法就符合開閉原則,如果新增四擋社保人員,他的方法只需要再額外擴(kuò)展一個(gè)四擋社保人員就可以,不用動(dòng)用其他代碼。
用了這個(gè)大家可能不太喜歡的看病的場(chǎng)景來描述這個(gè)開閉原則,不要忌諱哈,希望大家都健健康康,遠(yuǎn)離醫(yī)院。
總結(jié)
重申一下:對(duì)擴(kuò)展開放,對(duì)修改封閉。如果有同學(xué)經(jīng)常看一些開源框架源碼就會(huì)發(fā)現(xiàn),有很多很多抽象類和接口,debug 進(jìn)去很繞,其實(shí)這些抽象類和接口很多都是為了擴(kuò)展用,因?yàn)樽鳛殚_源框架,不得不實(shí)現(xiàn)各種可想象到的方案,而這些都基于開閉原則來實(shí)現(xiàn)的。以后有機(jī)會(huì)也可以寫一下源碼的文章分享給大家。
參考資料:《大話設(shè)計(jì)模式》、《Java設(shè)計(jì)模式》、《設(shè)計(jì)模式之禪》、《研磨設(shè)計(jì)模式》、《Head First 設(shè)計(jì)模式》
這周事情比較多,更新會(huì)不及時(shí),周五還要出差去一趟上海,周六回深圳,周日回一趟老家,各種奔波。。。
希望文章對(duì)您有所幫助,設(shè)計(jì)模式系列會(huì)持續(xù)更新,感興趣的同學(xué)可以關(guān)注公眾號(hào),第一時(shí)間獲取文章推送閱讀,也可以一起交流,交個(gè)朋友。
公眾號(hào)之設(shè)計(jì)模式系列文章
總結(jié)
- 上一篇: 无线加速度传感器
- 下一篇: 高效运维最佳实践:如何做好On-call