為什麼要用設計模式?先看看6大原則,要用設計模式原則
引言
本人不怎麼喜歡看書, 因為我看書一目十行, 看了就忘, 所以我這邊一邊看左老師的, 一邊抄, 增加自己的記憶力
這是左老哥的 http://www.cnblogs.com/zuoxiaolong/p/pattern1.html
直接進入正題, 相信大家入了這一行, 幾乎都忙的一筆, 但還是想要在閑時充下電. 我老想給自己充電, 時間也不少, 但是呢, 不玩上兩把遊戲不過癮, 讓大腦休息休息, 但是一玩遊戲就停不下來了, 要是我把玩遊戲的精神來學習java, 這句話怎麼這麼耳熟, 不管了, 先讀一讀設計模式.
ps 上面都是扯淡
學習設計模式, 就是為了讓我們顯著更加專業, 是的, 我們是專業coder
主體
學習設計模式之前, 我們需要先瞭解六大原則, 這原則看著很有道理
①單一原則:
意思: 只做一件事.
我用個虛擬碼表達一下
//計算檔案中的class Calculator {
//相加
public int add() throws NumberFormatException, IOException{ File file = new File("E:/data.txt"); BufferedReader br = new BufferedReader(new FileReader(file)); int a = Integer.valueOf(br.readLine()); int b = Integer.valueOf(br.readLine()); return a+b; }
}
要是誰封裝了這麼一個類, 然後你用了, 臥槽什麼怎麼只有加法, 沒有減法 乘法, 你然後是不是要 copy 一下 ,把+ 號改為其他符號 .
q:這個類中哪裡違反了單一原則呢?
梳理一下, 我們用這個計算類是為什麼幹什麼, 計算文本中的和
引申一下, 實際的操作步驟:
① 擷取檔案內容
② 計算傳回值
這個類同時擁有兩個職責
q:這個類還存在什麼問題?
在開發初期, 我們很有可能為了快速, 進行大量的copy, 這樣就導致了很多的代碼重複, 這樣可能我們為了書寫一個相減或相乘的方法, 來copy 加法中的代碼進行修改
下面我們需要把上面的代碼修改一下
//擷取檔案內容類別class Reader{ int a,b; public Reader(String path)throws Exception{ BufferedReader br = new BufferedReader(new FileReader(new File(path))); a= Integer.valueOf(br.readLine); b= Integer.valueOf(br.readLine); } int getA(){ return a; } int getB(){ return b; } }//單獨的計算類class Calculator{ int add(int , int b){ return a+b;} int subtract(int , int b){ return a-b;} }
這樣簡單明朗,意思深刻 ,當然這些都是我抄的大神的, 有時候沒有必要自己寫一些代碼, 跟著前輩走, 帶你少走很多彎路, 有時候總是走自己的路, 儘管得到的更多, 但是並不是每個人都是這樣的, 我是前者, 我明白自己的短板.
②裡氏替換原則
意思: 子類應該可以替換掉父類並且正常工作
子類一般不該重寫父類的方法, 因為父類的方法一般都是對外公開的.
但是在實際開發當中, 我們可能為了便利, 經常重寫父類的方法, 這樣就導致的子類和父類作了不同的功能,
下面我們用代碼來描述一下:
//父類class FatherClass{ public void eat(){ System.out.println("我愛吃米飯"); } }
//子類
class SonClass extends FatherClass{ void eat(){ System.out.println("我不愛吃米飯"); }}class SomeoneClass { @Test public void runLiSi(){ FatherClass fc = new FatherClass(); SonClass sc = new SonClass(); fc.eat(); sc.eat(); }}
上面這個例子, 父類和子類做同樣的事, 但是結果確實相反的
這個原則是在約束我們, 往往出現這種情況的時候, 我們需要考慮一下能不能, 效果如何.
③介面隔離原則(介面最小化原則)
開發中中 我們經常發現 我們在實現一個介面的同時, 有很多方法都是空的
直接上代碼
//手機介面public interface BaseMobile { public void call();//打電話 public void sendSms();//發簡訊 public void playBird();//玩遊戲 }
只要是手機那就應該有打電話發簡訊的功能, 但是玩遊戲的功能並不一定是每個手機都有的
所以我們可以先讓去掉 玩遊戲 這個介面 最小化這個介面
//修改後的代碼public interface BaseMobile { public void call(); public void sendSms(); }//適配器public interface IOSMobile extends BaseMobile{ public void playBird();}
這樣, 就很清晰的理解介面最小化原則,
但是凡事都有特例,
不需要發簡訊功能的手機存在嗎, 很顯然存在啊. 同樣的, 時代發展的很快, 手機的準系統也在變遷, 就像這樣是個手機應該就能上網之類的功能
ps:寫到這裡, 我明顯感覺我的思考問題的方式在發生著改變, 我們的代碼, 應該遵循的一些規範, 往往在人們的生活改變的同時改變著, 代碼離不開生活, 美好的生活由代碼構成, 在今後的社會, 有可能我們的代碼就像是科學一樣, 人人都應該瞭解她, 學習她.
④依賴倒置原則
高層模組不應該依賴與底層模組, 二者都應該依賴於抽象, 抽象不應該依賴於細節, 細節應該依賴於抽象
這句話意思就是, 不管你是北京人,還是北京朝陽群眾, 你都是中國人, 這麼理解就沒錯了. 實際上, 我還是感覺上句話好理解一點.
下面我們直接用代碼來表示一下
//抽象 人public interface People{ void myInfo();//自我介紹 void canDo();//能做什麼}//中國人 public class China:People{ public void myInfo(){ System.out.println("我是中國人"); } void canDo(){ System.out.println("我會code,搬磚,修車,開車,滑稽"); }} //美國人public class America:People{ public void myInfo(){ System.out.println("我是美國人"); } void canDo(){ System.out.println("我會code,mygod,yea,aye,huhuh"); }} //高層 public class PeopleInfo{private People people;public PeopleInfo(People people){ this.people =people;} public void myInfo(){ people.myInfo(); } void canDo(){ people.canDo();}}
現在PeopleInfo這個類依賴於People, 而具體方法不會影響PeopleInfo , 只要改變實現People即可 ,也就是細節依賴於抽象
並且 PeopleInfo 不依賴於China和America, 也就是依賴關係被倒置了
這裡我解釋下可能有的同學不是很清楚其中的利害 依賴倒置
PeopleInfo 依賴於 People ,當我們需要使用PeopleInfo做某些事情的時候, 這時需要注入China或其他實作類別, 但是PeopleInfo並不依賴China,
PeopleInfo只依賴People .
想象一下, 我們使用PeopleInfo, 注入China,使用myInfo()的結果:我是china. 注入America,使用myInfo()的結果:我是America.
q:說明PeopleInfo不依賴 China 和America ,但是怎麼能調用它們的方法呢?
反過來想下, 我想要使用China myInfo()方法 有兩個方法
第一種 直接new 是不是有點粗暴
第二種 把China 注入PeopleInfo 專業code啊
第二種 China反而依賴於PeopleInfo 依賴就這麼反轉了, 這是我目前的理解,有問題, 大家可以指出來
⑤迪米特原則
最小知道原則, 一個類盡量不應該知道其他類太多的東西,不要有太多的接觸
大白話, 就是一個類不應該依賴其他的類太多細節, 其他類不應該對外提供太多細節, 要高內聚, 低耦合
先來個不符合這個原則的
//低內聚public class LowCohesion{ private String name; private int age; private boolean openMouth = false; public LowCohesion(String name, int age){ this.name = name; this.age = age; } public void setOpenMouth(boolean boo){ this.openMouth = boo; } public saySelf(){ if(openMouth){ System.out.println("大家好,我叫"+name+", 今年"+age+"了"); }else{ System.out.println("......"); } }}//用戶端public class client{ public static void main(String[] args) throws Exception { LowCohesion lc= new LowCohesion("老哥",26);//來了個老哥 lc.setOpenMouth(true);//老哥張嘴 lc.saySelf();//老哥說話 }}
假設我們是面試官, 來個人,我們一般只需要讓人自我介紹 , 也就是 saySelf ,這個例子裡面我們需要openMouth,這就是 類不應該依賴其他的類太多細節
這個動作可以是外驅的 但是這個細節完全沒必要暴露出去, 我們要的是自我介紹, 而不是 先我准許你說話 , 然後你可以自我介紹, saySelf這個動作應該內建 openMouth , 也就是 其他類不應該對外提供太多細節
我的表達可能不是很準確, 迪米特原則,我的理解是雙向約束的規則, 其中主要是針對 類的內聚性
⑥開閉原則
對修改關閉, 對擴充開發.
在實際開發中, 我們由於各種情境需求, 需要修改大量的原有的代碼, 很多項目都是非常的趕, 擴充性, 項目有二開就有擴充性
有時候我感覺自己可以掌控一方, 但是實際真的什麼都不懂, 再次感覺前輩們, 我會堅持下去