如果你認為封裝僅僅是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