引言
本人不怎麼喜歡看書, 因為我看書一目十行, 看了就忘, 所以我這邊一邊看左老師的, 一邊抄, 增加自己的記憶力
這是左老哥的 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 , 也就是 其他類不應該對外提供太多細節
我的表達可能不是很准確, 迪米特原則,我的理解是雙向約束的規則, 其中主要是針對 類的內聚性
⑥開閉原則
對修改關閉, 對擴展開發.
在實際開發中, 我們由於各種場景需求, 需要修改大量的原有的代碼, 很多項目都是非常的趕, 擴展性, 項目有二開就有擴展性
有時候我感覺自己可以掌控一方, 但是實際真的什麼都不懂, 再次感覺前輩們, 我會堅持下去