重新認識java(二) ---- 面向?qū)ο笾庋b!

如果你認為封裝僅僅是private + getter and setter,那你就大錯特錯了!

什么是封裝

對于面向?qū)ο蟮奶攸c,我想大家都可以倒背如流了:封裝,繼承,多態(tài)。很多人對這些特點的理解僅僅停留在表面。以為封裝就是變量私有化,然后對外提供接口,而不知為什么要這樣做。

封裝,簡單的來講就是將變量的屬性私有化,在java里就是用private修飾符修飾,這樣在外部產(chǎn)生的對象就不能直接訪問到這個變量。想要對變量進行操作或者訪問,就需要在類里提供外部訪問的接口,也就是我們熟知的get和set方法。

這就是大部分人對封裝的理解。知道有封裝這回事,知道怎么用,卻不知道為什么要用,甚至覺得這是多此一舉。因為明明person.name就可以訪問到變量,為什么非要person.getName()呢?

任性的使用public

我們先來看一下不使用封裝的情況。

首先,有兩個類,Man和Women:

//Man
public class Man {
    public String name; //名字
    public Woman wife;  //男人嘛,都有妻子
    public double money;//男人嘛,多賺點錢

    //還可以結(jié)個婚
    public void marry(Woman woman){
        this.wife = woman;
        woman.marry(this);
    }
}
//Women
public class Woman {
    public String name; //名字
    public Man husband; //得有一個丈夫
    //也可以結(jié)個婚
    public void marry(Man man){
        this.husband = man;
    }
}

代碼很精簡,看著很舒服,測試一下。

哎喲,看起來還不錯。

這個時候,來了一個小偷,這小偷不干別的,就偷別人的錢和老婆。

//小偷
public class Thief {
    private double stealMoney = 0;
    private List<Woman> womens = new ArrayList<>();

    //偷錢
    public void stealMoney(Man man){
        stealMoney += man.money;
        man.money = 0;
        System.out.println("哈哈,偷到錢了");
    }
    //偷老婆,最可氣的是,偷了你的老婆還把鳳姐丟給了你
    public void stealWife(Man man){
        womens.add(man.wife);
        Woman woman = new Woman();
        woman.name = "鳳姐";
        man.wife = woman;
        System.out.println("哈哈哈,又偷了一個妹紙");
    }
}

有一天,來了這么一個小偷:

傻了吧?你老婆呢?你錢呢?哈哈哈哈哈哈哈哈哈

就這樣,小偷偷走了你的錢和你的老婆并丟給了你一個鳳姐,而你,卻無能為力。

你覺得必須要改變一下了??!

封裝前來報到

封裝覺得你有點慘,于是過來幫了一下你:

//PackageMan
public class PackageMan {
    private String name; //私有化名字
    private PackageWoman wife;//必須私有??!必須!
    private double money; //私有,統(tǒng)統(tǒng)私有!
    //我們先寫個構(gòu)造函數(shù),為了方便
    public PackageMan(String name, double money) {
        this.name = name;
        this.money = money;
    }
    //結(jié)婚
    public void marry(PackageWoman woman){
        this.wife = woman;
        woman.marry(this);
    }

    //各種getter和setter
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public PackageWoman getWife() {
        return wife;
    }

    public double getMoney() {
        return money;
    }
}

//PackageWoman
public class PackageWoman {
    private String name;
    private PackageMan husband;

    public void marry(PackageMan man){
        this.husband = man;
    }

    public PackageWoman(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public PackageMan getHusband() {
        return husband;
    }

    public void setName(String name) {
        this.name = name;
    }
}

看起來有點眼花繚亂,這樣真的有效么?

恩,看起來還行,就是代碼長了點,趕緊給我來個小偷測試一下!

什么?你想測試一下,不好意思,測試不了,因為小偷已經(jīng)死在測試的路上了。因為我們根本沒有對外提供設置money和wife的方法,所以小偷可以知道你有多少錢,知道你有一個漂亮的老婆,但是他卻無能為力,因為他只能看著。

細心的人也許發(fā)現(xiàn)了,這里面有一個很嚴重的問題:

沒錯,小偷不能把我們的money清空了,也不能將我們的wife換成別人了。但是,如果我們要自己換呢?我的錢這輩子就這么點?還不能花?我還不能離婚了?(咳咳。。不鼓勵離婚哈,就是舉個例子,別打我)

這才是封裝厲害的地方

如何解決上面的問題呢?私有化外部訪問不到,自己也沒法改變數(shù)據(jù),提供set方法又會讓所有人都能改,和不私有沒什么區(qū)別,好糾結(jié)啊。

等等,你剛剛說 “所有人“?真的是所有人么?

我們來看看:

public void setMoney(PackageMan man,double money) {
    if (man == this) {
        this.money = money;
    } else {
        System.out.println("喂,110嗎?"+man.getName()+"搶錢!");
    }
}

這樣呢?只有你自己可以修改,別人都不可以,測試一下:

這樣就可以了,自己可以修改,但是別人不可以。

但是你老婆不滿意了,憑什么只有你自己能改?我也想改!

這種要求,還是應該滿足一下的,怎么做呢?

public void setMoney(Object o,double money) {
    if (o == this || o == this.wife) {
        this.money = money;
    } else {
        System.out.println("喂,110嗎?有人搶錢!");
    }
}

這樣就可以了。

當然,愛思考的人肯定發(fā)現(xiàn)了,我把搶錢的那句話修改了,沒有獲取修改人的名字,因為傳入的是Objects對象。當然,你也可以再寫點代碼,判斷一下傳進來的是什么,然后搶轉(zhuǎn)為相應的類型,再調(diào)用相應的方法。

除此之外,就沒有別的辦法了么?當然有,具體怎么做,我們下一篇文章再做分解。下一篇文章《重新認識java(三) ---- 面向?qū)ο笾^承》不定期更新。

仔細思考一下你會發(fā)現(xiàn),我特么竟然是在騙你!因為當你提供了set函數(shù)以后,小偷又可以偷你的東西了。仔細看一下之前小偷是怎么偷你東西的你就知道了。

沒錯,就是通過你自己。小偷通過你自己改變了你自己。聽起來有點扯,但是事實上就是這樣的。

那么,有沒有一種辦法讓小偷在只得到”你自己“的情況下怎么樣都不能改變“你的屬性值”,而只有你自己能改變呢?

大家可以自己想想,具體的解決辦法,我們在之后的文章里揭曉。敬請期待。

總結(jié)一下

以上就是面向?qū)ο蟮姆庋b,封裝不僅僅只是private + getter and setter。使用封裝可以對setter進行更深層次的定制。你可以對可以執(zhí)行setter方法的對象做規(guī)定,也可以對數(shù)據(jù)作要求,還可以做類型轉(zhuǎn)換等等一系列你可以想到的。

使用封裝不僅僅是安全,更可以簡化操作。不要覺得用了封裝多了好多代碼,看起來亂糟糟的。這只是因為我舉得例子太小了。如果你寫你個大的系統(tǒng),一開始你的這樣定義類的

public int age;

你的程序里大概有100處這樣的語句:

p.age = 10;

這個時候,突然要求你把數(shù)據(jù)類型變了,改成:

public String age;

你是不是要把那100處數(shù)據(jù)都加個雙引號呢?這是不是很麻煩?

如果你用了封裝,你只需要這樣:

public void setAge(int age){
    this.age = String.valueOf(age);
}

然后就搞定了,是不是簡化了操作?

我只是舉個例子,實際開發(fā)中也不會出現(xiàn)改變數(shù)據(jù)類型這么操蛋的事。。

封裝還有一個好處是模塊化。當你參與一個很多人實現(xiàn)的大型系統(tǒng)中,你不可能知道所有的類是怎樣實現(xiàn)的。你只需要知道這個類給我提供了哪些方法,我需要傳入什么數(shù)據(jù),我能得到什么結(jié)果。至于怎么得到的,關(guān)我x事?

所以說,如果你寫的代碼還沒有用封裝,改過來吧。不是因為大家都用所以你也應該用,而是這確實可以給你提供極大的便利。

結(jié)束~


有什么疑問或者錯誤可以給我留言

下篇文章見~

轉(zhuǎn)載請注明出處?。。。?!
本文原創(chuàng)自csdn和簡書??!
csdn地址:http://m.blog.csdn.net/article/details?id=53381737
簡書地址:http://www.itdecent.cn/p/9cc3a832fabb

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容