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