摘要:前言關(guān)于設(shè)計(jì)模式,想必大家的第一感覺(jué)就是過(guò)于高深,有點(diǎn)虛吧。為什么要學(xué)習(xí)設(shè)計(jì)模式因?yàn)橐b逼啊咳咳,大家請(qǐng)忽略前面那句話。處處都是設(shè)計(jì)模式的體現(xiàn),所以若想攻下,設(shè)計(jì)模式是必學(xué)的。下節(jié)預(yù)告單例模式
前言
關(guān)于設(shè)計(jì)模式,想必大家的第一感覺(jué)就是過(guò)于高深,有點(diǎn)虛吧。相對(duì)來(lái)說(shuō),我們還是更熟悉ssh或者ssm之類的開(kāi)發(fā)框架,一個(gè)工具用久了就會(huì)熟能生巧,就像刷漆工,時(shí)間長(zhǎng)了也知道如何刷的一手漂亮的好墻。我們把springmvc用的很溜,把mybatis用的很溜,但這只是一個(gè)合格的程序員應(yīng)該具備的能力之一。于是我們便成為了代碼工人,想站在更高角度去設(shè)計(jì),設(shè)計(jì)模式是必不可少的。簡(jiǎn)介
廢話那么多,我們直接進(jìn)入正題呢,到底什么是設(shè)計(jì)模式呢?我在設(shè)計(jì)模式之禪上摘抄出這一句話:
為什么要學(xué)習(xí)設(shè)計(jì)模式設(shè)計(jì)模式(Designpattern)是一套理論,由軟件界的先輩們總結(jié)出的一套可以反復(fù)使用的經(jīng)驗(yàn),它可以提高代碼的可重用性,增強(qiáng)系統(tǒng)的可維護(hù)性,以及解決一系列的復(fù)雜問(wèn)題。
因?yàn)橐b逼啊...咳咳,大家請(qǐng)忽略前面那句話。相信大家都有閱讀spring源碼的經(jīng)歷吧,看到類層次設(shè)計(jì)圖,為什么會(huì)有這么多的接口,這么多的抽象類,這么多實(shí)現(xiàn),心里有一萬(wàn)只草泥馬狂奔而過(guò)。spring處處都是設(shè)計(jì)模式的體現(xiàn),所以若想攻下spring,設(shè)計(jì)模式是必學(xué)的。其次,作為一個(gè)coder,最煩的就是需求變更,我們可以分析現(xiàn)有的需求,預(yù)測(cè)可能發(fā)生的變更,但是我們不能控制需求的變更。既然需求不可變更,那如何擁抱變化呢?設(shè)計(jì)模式給了我們知道,提出了6大原則,在此基礎(chǔ)上提出了23種設(shè)計(jì)模式。如果你通曉了23種設(shè)計(jì)模式,那你就可以站在一個(gè)更高的層次去賞析程序代碼,完成從代碼工人到架構(gòu)師的轉(zhuǎn)變~>~.
設(shè)計(jì)模式六大原則 單一職責(zé)原則(最容易理解,最難實(shí)施的一個(gè)原則)描述:應(yīng)該有且僅有一個(gè)原因引起類的變更 相信大家已經(jīng)很不屑了,切,這么簡(jiǎn)單的東西還拿出來(lái)說(shuō)??墒堑览砗?jiǎn)單實(shí)現(xiàn)難啊。下面我給大家示例一些代碼: public interface IUserInfo { void setUserName(String name); void setUserAge(int age); void walk(); void seeMovie(); void addRole(Role role); } 相信初級(jí)程序員都不會(huì)犯這樣的錯(cuò),將用戶信息和用戶行為放在同一個(gè)類里。最佳的做法就是將用戶信息和用戶行為分開(kāi)管理,加角色動(dòng)作也應(yīng)該放在相應(yīng)的實(shí)現(xiàn)類里。這是我臨時(shí)想的例子,雖然很簡(jiǎn)單,但足以表達(dá)單一原則的意思。單一職責(zé)原則最難劃分的就是職責(zé),職責(zé)沒(méi)有量化的標(biāo)準(zhǔn),職責(zé)劃分的過(guò)于細(xì),類的數(shù)量會(huì)暴增,系統(tǒng)復(fù)雜度會(huì)以指數(shù)趨勢(shì)增長(zhǎng),所以建議是接口一定要做到單一職責(zé),累類設(shè)計(jì)盡量做到單一職責(zé)。里氏替換原則(使用時(shí)一定要注意子類的個(gè)性化..)
描述:所有引用基類的地方必須能透明地使用其子類的對(duì)象。 java與c++不同,java是一門(mén)單根繼承的語(yǔ)言。使用extend關(guān)鍵字聲明繼承,若不使用,則代表繼承Object。子類繼承父類,會(huì)擁有父類的方法和屬性,很多開(kāi)源框架的擴(kuò)展接口都是通過(guò)繼承父類來(lái)完成的。通過(guò)這個(gè)特性,我們明白只要父類存在的地方,我們都可以替換成子類,并且編譯器不會(huì)報(bào)錯(cuò)。但是java允許子類重寫(xiě)父類方法,這種子類的個(gè)性化有時(shí)會(huì)嚴(yán)重違背里氏替換原則.給大家上個(gè)示例:
public class AnyClazz{ //有某一個(gè)方法,使用了一個(gè)父類類型 public void someoneMethod(Parent parent){ parent.method(); } } public class Parent { public void method(){ System.out.println("parent method"); } } public class SubClass extends Parent{ //結(jié)果某一個(gè)子類重寫(xiě)了父類的方法,說(shuō)不支持該操作了 public void method() { throw new Exception(); } } public class Test{ public static void main(String[] args) { AnyClazz anyClazz = new AnyClazz(); anyClazz.someoneMethod(new Parent()); anyClazz.someoneMethod(new SubClass()); } }
程序運(yùn)行結(jié)果肯定會(huì)報(bào)錯(cuò),這就相當(dāng)于我們埋了一個(gè)雷,子類復(fù)寫(xiě)父類方法,編譯期不報(bào)錯(cuò),運(yùn)行期就會(huì)報(bào)錯(cuò)。所以建議在項(xiàng)目中使用此原則時(shí),應(yīng)盡量避免子類的個(gè)性,一旦子類有個(gè)性,子類和父類的矛盾將可能直接破壞整個(gè)程序。
依賴倒置原則(很常見(jiàn),現(xiàn)在的企業(yè)開(kāi)發(fā)中業(yè)務(wù)層都有對(duì)應(yīng)接口)描述:面向接口編程。 在Java中的語(yǔ)言表現(xiàn)就是:模塊間的依賴通過(guò)抽象發(fā)生,實(shí)現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過(guò)接口或抽象類發(fā)生的。接口和抽象類不依賴于實(shí)現(xiàn)類。實(shí)現(xiàn)類依賴接口或抽象類。簡(jiǎn)而言之,就是之前的描述~~。給大家舉個(gè)例子:
public class Cooker { public void work(){ System.out.println("我會(huì)做飯"); } } public class Boss { public void recruitPerson (Cooker cooker){ cooker.work(); } } public class Test { public static void main(String[] args) { Boss boss = new Boss(); boss.recruitPerson(new Cooker()); } } 運(yùn)行結(jié)果:我會(huì)做飯
上面代碼一個(gè)大老板剛開(kāi)了一個(gè)超市,在招廚師。假如我們要是招大堂經(jīng)理怎么辦?創(chuàng)建經(jīng)理類,在boss中增加招經(jīng)理的方法同時(shí)在test中修改。這樣改好嗎??jī)H僅是需求改了一點(diǎn)點(diǎn),我們就要在所有代碼里進(jìn)行一些改動(dòng),這代價(jià)也太大了吧,耦合性忒高了~ 不要著急,依賴倒置原則可以幫我們解決這個(gè)問(wèn)題,它可以減少類間的耦合性,提高系統(tǒng)的穩(wěn)定性,降低并行開(kāi)發(fā)引起的風(fēng)險(xiǎn),提高代碼可讀性和維護(hù)性。修改之后的例子如下:
public interface IWorker { void work(); } public class Cooker implements IWorker { @Override public void work(){ System.out.println("我會(huì)做飯"); } } public class Manager implements IWorker { @Override public void work() { System.out.println("糊弄老板,指揮其他人干活"); } } public interface IBoss { void recruitPerson(IWorker iWorker); } public class Boss implements IBoss{ @Override public void recruitPerson(IWorker iWorker) { iWorker.work(); } } public class Test { public static void main(String[] args) { Boss boss = new Boss(); IWorker iWorker = new Manager(); boss.recruitPerson(iWorker); } } 運(yùn)行結(jié)果: 糊弄老板,指揮其他人干活
咋一看,類變得更多了..使用技術(shù)總是要有點(diǎn)成本的嗎,但假如以后我們?cè)谠黾诱欣碡泦T,招收銀員等等改動(dòng)就小了。其實(shí)這個(gè)原則的本質(zhì)就是通過(guò)抽象是各個(gè)類和模塊的實(shí)現(xiàn)獨(dú)立,不互相影響,實(shí)現(xiàn)松耦合。接口隔離原則(六大原則中身材最好的那個(gè)小姐姐)
描述:接口盡量細(xì)化,同時(shí)接口中方法盡量少。 看到上面的描述可能會(huì)有點(diǎn)疑惑,這個(gè)和第一個(gè)的小姐姐(單一職責(zé)原則)有點(diǎn)像啊。單一職責(zé)衡量的是類的和接口職責(zé)要單一,對(duì),是職責(zé)!而接口隔離原則就只是要求接口的粒度盡可能的小,最好就是一個(gè)接口一個(gè)方法(這是完美符合接口隔離原則的),不過(guò)這樣做的話是明顯要被其他小伙伴干死的(2333~~~)。接口粒度太小,接口數(shù)就會(huì)暴增,開(kāi)發(fā)人員嗆死在接口的海洋里,接口粒度太大,靈活性降低,無(wú)法提供定制服務(wù)。給大家舉個(gè)例子:
//美食 public interface ICate { void goodLool(); void niceTaste(); void cleanFood(); } public class Cate implements ICate{ @Override public void goodLool() { System.out.println("色相看起來(lái)很好O(∩_∩)O哈哈~"); } @Override public void niceTaste() { System.out.println("吃起來(lái),味絕了(*^▽^*)"); } @Override public void cleanFood() { System.out.println("食材很干凈,食用放心"); } } public abstract class AbstractPerson { protected ICate iCate; public AbstractPerson(ICate iCate) { this.iCate = iCate; } abstract void eat(); } public class Person extends AbstractPerson { public Person(ICate iCate) { super(iCate); } @Override void eat() { iCate.cleanFood(); iCate.goodLool(); iCate.niceTaste(); } } public class Test { public static void main(String[] args) { ICate iCate = new Cate(); AbstractPerson abstractPerson = new Person(iCate); abstractPerson.eat(); } } 運(yùn)行結(jié)果: 食材很干凈,食用放心 色相看起來(lái)很好O(∩_∩)O哈哈~ 吃起來(lái),味絕了(*^▽^*)
上面的例子我去吃美食,我對(duì)美食的標(biāo)準(zhǔn)是看起來(lái),聞起來(lái)像,吃起來(lái)放心(吃貨up!up!)??墒敲總€(gè)人對(duì)美食的標(biāo)準(zhǔn)都是一樣的,你總不能因?yàn)槌舳垢勂饋?lái)很臭就不是美食吧??墒乾F(xiàn)在接口定義了只有三個(gè)條件都滿足才能叫美食,這個(gè)該怎么辦?難道要再擴(kuò)展一個(gè)美食接口,只定義味道標(biāo)準(zhǔn),可是我們的抽象類依賴的是ICate接口,我們的person又怎么只根據(jù)味道去分辨是不是美食呢?我們采用接口隔離原則去細(xì)化接口,示例如下:
public interface IGoodLookCate { void goodLook(); } public interface IGoodTasteCate { void niceTaste(); void cleanFood(); } public class Cate implements IGoodLookCate,IGoodTasteCate{ @Override public void goodLook() { System.out.println("色相看起來(lái)很好O(∩_∩)O哈哈~"); } @Override public void niceTaste() { System.out.println("吃起來(lái),味絕了(*^▽^*)"); } @Override public void cleanFood() { System.out.println("食材很干凈,食用放心"); } }
通過(guò)這樣的重構(gòu)后,不僅是要好吃的美食還是要好看的美食,都可以保持接口的穩(wěn)定。當(dāng)然你如果要說(shuō)美食的標(biāo)準(zhǔn)又變了,接口還得改。沒(méi)錯(cuò),但是設(shè)計(jì)是有限度的,不能無(wú)限考慮未來(lái),不然會(huì)陷入到過(guò)度設(shè)計(jì)的泥潭當(dāng)中。迪米特法則(六大原則中最害羞的小姐姐)
描述:一個(gè)對(duì)象盡量不要知道太多關(guān)于其他對(duì)象的事
這個(gè)原則的核心觀念就是類間解耦,低耦合。通俗一點(diǎn)來(lái)講就是1.只和朋友交流2.朋友之間也是有距離的。舉個(gè)例子說(shuō)明下吧:
public class Goods { } public class Worker { public void sendGoods(Listlist){ System.out.println("送貨嘍:"+list); } } public class Boss { private static final List list = new ArrayList (); static { list.add(new Goods()); list.add(new Goods()); list.add(new Goods()); } public static void main(String[] args) { Worker worker = new Worker(); worker.sendGoods(list); } }
工人送貨的場(chǎng)景,老板和工人是直接關(guān)系,工人和貨物是直接關(guān)系,但是代碼中老板和貨物也攪在了一起,出現(xiàn)了過(guò)多依賴,破壞了老板類的健壯性,已經(jīng)違反了迪米特法則。正確做法應(yīng)該是將貨物的邏輯抽取到工人當(dāng)中(因?yàn)榉浅:?jiǎn)單,就不上代碼示例了)。朋友之間也是有距離的應(yīng)當(dāng)如何理解呢?假如類A提供了getA(),getB(),getC()三個(gè)方法,類B在邏輯內(nèi)對(duì)ABC三個(gè)方法進(jìn)行調(diào)用或者根據(jù)其返回值決定邏輯,這樣也違反了迪米特法則,正確做法應(yīng)是將對(duì)ABC三個(gè)方法調(diào)用的邏輯抽取封裝到A中,同時(shí)將ABC三個(gè)方法進(jìn)行私有化。
開(kāi)閉原則(六大原則中當(dāng)之無(wú)愧的大姐大)描述:對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉
開(kāi)閉原則是六大原則里的精神領(lǐng)袖,也是最虛的原則。前面五個(gè)原則就是對(duì)開(kāi)閉原則的具體解釋。意思就是現(xiàn)在的系統(tǒng)中,不需要修改原有的代碼,只需要擴(kuò)展一些新的實(shí)現(xiàn)就可以搞定。但是沒(méi)有任何一個(gè)系統(tǒng)可以做到,哪怕是spring也不可以,雖說(shuō)他的擴(kuò)展性已經(jīng)強(qiáng)的{{BANNED}}。
以上6個(gè)原則是為了之后23種設(shè)計(jì)模式的描述,基本上都是我自己的理解,或許形容有好有差,不需要在意,各位完全可以有自己的理解。
下節(jié)預(yù)告:?jiǎn)卫J?/b>文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68019.html
摘要:探究系統(tǒng)登錄驗(yàn)證碼的實(shí)現(xiàn)后端掘金驗(yàn)證碼生成類手把手教程后端博客系統(tǒng)第一章掘金轉(zhuǎn)眼間時(shí)間就從月份到現(xiàn)在的十一月份了。提供了與標(biāo)準(zhǔn)不同的工作方式我的后端書(shū)架后端掘金我的后端書(shū)架月前本書(shū)架主要針對(duì)后端開(kāi)發(fā)與架構(gòu)。 Spring Boot干貨系列總綱 | 掘金技術(shù)征文 - 掘金原本地址:Spring Boot干貨系列總綱博客地址:http://tengj.top/ 前言 博主16年認(rèn)識(shí)Spin...
摘要:不知不覺(jué)寫(xiě)已經(jīng)將近年時(shí)間了,在其中嘗試著看了一下其它語(yǔ)言,發(fā)現(xiàn)其它語(yǔ)言都有很好的調(diào)試工具,協(xié)助調(diào)試和開(kāi)發(fā)。難道就能依靠這樣的斷點(diǎn)調(diào)試么直到我發(fā)現(xiàn)了說(shuō)來(lái)慚愧,這么久才發(fā)現(xiàn),才發(fā)現(xiàn)是真心好用,于是花點(diǎn)時(shí)間總結(jié)一下,大致的內(nèi)容框架如下 不知不覺(jué)寫(xiě)php已經(jīng)將近5年時(shí)間了,在其中嘗試著看了一下其它語(yǔ)言,發(fā)現(xiàn)其它語(yǔ)言都有很好的調(diào)試工具,協(xié)助調(diào)試和開(kāi)發(fā)。難道php就能依靠var_dump 、ech...
摘要:我打算寫(xiě)一個(gè)鏈表操作的系列,來(lái)自的系列,實(shí)現(xiàn)語(yǔ)言是。通過(guò)自己實(shí)現(xiàn)一個(gè)鏈表和常用操作,可以加深理解這類數(shù)據(jù)結(jié)構(gòu)的優(yōu)缺點(diǎn)。鏈表經(jīng)常用來(lái)訓(xùn)練指針操作,雖然這只對(duì)適用,但等高級(jí)語(yǔ)言中控制引用的思路其實(shí)也差不多。 TL;DR 我打算寫(xiě)一個(gè)鏈表操作的系列,來(lái)自 Codewars 的 Linked List 系列 kata ,實(shí)現(xiàn)語(yǔ)言是 JavaScript 。這篇是開(kāi)篇,簡(jiǎn)單描述了一下我寫(xiě)這個(gè)的目...
摘要:系列文章更新計(jì)劃列表主要對(duì)一些中常用的框架進(jìn)行簡(jiǎn)單的介紹及快速上手,外加相關(guān)資料的收集更新列表會(huì)不定期的加入新的內(nèi)容以進(jìn)行擴(kuò)充,如果你對(duì)此感興趣可以站內(nèi)聯(lián)系我。 導(dǎo)讀: 從第一次接觸Spring Boot 至今已經(jīng)有半年多了,在這期間也瀏覽了許多和Spring Boot 相關(guān)的書(shū)籍及文章,公司里面的許多項(xiàng)目也一直在使用Spring Boot。關(guān)于Spring Boot的一些看法:Spr...
閱讀 1175·2021-11-16 11:45
閱讀 1042·2021-09-04 16:41
閱讀 3088·2019-08-29 16:40
閱讀 2865·2019-08-29 15:34
閱讀 2681·2019-08-29 13:11
閱讀 1743·2019-08-29 12:58
閱讀 1735·2019-08-28 18:00
閱讀 1785·2019-08-26 18:26