如果你認(rèn)為封裝僅僅是private + getter and setter乐纸,那你就大錯(cuò)特錯(cuò)了衬廷!
什么是封裝
對于面向?qū)ο蟮奶攸c(diǎn),我想大家都可以倒背如流了:封裝汽绢,繼承吗跋,多態(tài)。很多人對這些特點(diǎn)的理解僅僅停留在表面宁昭。以為封裝就是變量私有化跌宛,然后對外提供接口,而不知為什么要這樣做积仗。
封裝疆拘,簡單的來講就是將變量的屬性私有化,在java里就是用private修飾符修飾寂曹,這樣在外部產(chǎn)生的對象就不能直接訪問到這個(gè)變量哎迄。想要對變量進(jìn)行操作或者訪問回右,就需要在類里提供外部訪問的接口,也就是我們熟知的get和set方法漱挚。
這就是大部分人對封裝的理解翔烁。知道有封裝這回事,知道怎么用棱烂,卻不知道為什么要用租漂,甚至覺得這是多此一舉阶女。因?yàn)槊髅?code>person.name就可以訪問到變量颊糜,為什么非要person.getName()
呢?
任性的使用public
我們先來看一下不使用封裝的情況秃踩。
首先衬鱼,有兩個(gè)類,Man和Women:
//Man
public class Man {
public String name; //名字
public Woman wife; //男人嘛憔杨,都有妻子
public double money;//男人嘛鸟赫,多賺點(diǎn)錢
//還可以結(jié)個(gè)婚
public void marry(Woman woman){
this.wife = woman;
woman.marry(this);
}
}
//Women
public class Woman {
public String name; //名字
public Man husband; //得有一個(gè)丈夫
//也可以結(jié)個(gè)婚
public void marry(Man man){
this.husband = man;
}
}
代碼很精簡,看著很舒服消别,測試一下抛蚤。
哎喲,看起來還不錯(cuò)寻狂。
這個(gè)時(shí)候岁经,來了一個(gè)小偷,這小偷不干別的蛇券,就偷別人的錢和老婆缀壤。
//小偷
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("哈哈哈,又偷了一個(gè)妹紙");
}
}
有一天蒂胞,來了這么一個(gè)小偷:
傻了吧图呢?你老婆呢?你錢呢骗随?哈哈哈哈哈哈哈哈哈
就這樣岳瞭,小偷偷走了你的錢和你的老婆并丟給了你一個(gè)鳳姐,而你蚊锹,卻無能為力瞳筏。
你覺得必須要改變一下了!牡昆!
封裝前來報(bào)到
封裝覺得你有點(diǎn)慘姚炕,于是過來幫了一下你:
//PackageMan
public class PackageMan {
private String name; //私有化名字
private PackageWoman wife;//必須私有L贰!必須柱宦!
private double money; //私有些椒,統(tǒng)統(tǒng)私有!
//我們先寫個(gè)構(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;
}
}
看起來有點(diǎn)眼花繚亂免糕,這樣真的有效么?
恩忧侧,看起來還行石窑,就是代碼長了點(diǎn),趕緊給我來個(gè)小偷測試一下蚓炬!
什么松逊?你想測試一下,不好意思肯夏,測試不了经宏,因?yàn)樾⊥狄呀?jīng)死在測試的路上了。因?yàn)槲覀兏緵]有對外提供設(shè)置money和wife的方法驯击,所以小偷可以知道你有多少錢烁兰,知道你有一個(gè)漂亮的老婆,但是他卻無能為力徊都,因?yàn)樗荒芸粗?/p>
細(xì)心的人也許發(fā)現(xiàn)了沪斟,這里面有一個(gè)很嚴(yán)重的問題:
沒錯(cuò),小偷不能把我們的money清空了碟贾,也不能將我們的wife換成別人了币喧。但是,如果我們要自己換呢袱耽?我的錢這輩子就這么點(diǎn)杀餐?還不能花?我還不能離婚了朱巨?(咳咳史翘。。不鼓勵離婚哈冀续,就是舉個(gè)例子琼讽,別打我)
這才是封裝厲害的地方
如何解決上面的問題呢?私有化外部訪問不到洪唐,自己也沒法改變數(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()+"搶錢注整!");
}
}
這樣呢能曾?只有你自己可以修改,別人都不可以肿轨,測試一下:
這樣就可以了寿冕,自己可以修改,但是別人不可以萝招。
但是你老婆不滿意了蚂斤,憑什么只有你自己能改存捺?我也想改槐沼!
這種要求,還是應(yīng)該滿足一下的捌治,怎么做呢岗钩?
public void setMoney(Object o,double money) {
if (o == this || o == this.wife) {
this.money = money;
} else {
System.out.println("喂,110嗎肖油?有人搶錢兼吓!");
}
}
這樣就可以了。
當(dāng)然森枪,愛思考的人肯定發(fā)現(xiàn)了视搏,我把搶錢的那句話修改了,沒有獲取修改人的名字县袱,因?yàn)閭魅氲氖荗bjects對象浑娜。當(dāng)然,你也可以再寫點(diǎn)代碼式散,判斷一下傳進(jìn)來的是什么筋遭,然后搶轉(zhuǎn)為相應(yīng)的類型,再調(diào)用相應(yīng)的方法暴拄。
除此之外漓滔,就沒有別的辦法了么?當(dāng)然有乖篷,具體怎么做响驴,我們下一篇文章再做分解。下一篇文章《重新認(rèn)識java(三) ---- 面向?qū)ο笾^承》不定期更新撕蔼。
仔細(xì)思考一下你會發(fā)現(xiàn)豁鲤,我特么竟然是在騙你石蔗!因?yàn)楫?dāng)你提供了set函數(shù)以后,小偷又可以偷你的東西了畅形。仔細(xì)看一下之前小偷是怎么偷你東西的你就知道了养距。
沒錯(cuò),就是通過你自己日熬。小偷通過你自己改變了你自己棍厌。聽起來有點(diǎn)扯,但是事實(shí)上就是這樣的竖席。
那么耘纱,有沒有一種辦法讓小偷在只得到”你自己“的情況下怎么樣都不能改變“你的屬性值”,而只有你自己能改變呢毕荐?
大家可以自己想想束析,具體的解決辦法,我們在之后的文章里揭曉憎亚。敬請期待员寇。
總結(jié)一下
以上就是面向?qū)ο蟮姆庋b,封裝不僅僅只是private + getter and setter第美。使用封裝可以對setter進(jìn)行更深層次的定制蝶锋。你可以對可以執(zhí)行setter方法的對象做規(guī)定,也可以對數(shù)據(jù)作要求什往,還可以做類型轉(zhuǎn)換等等一系列你可以想到的扳缕。
使用封裝不僅僅是安全,更可以簡化操作别威。不要覺得用了封裝多了好多代碼躯舔,看起來亂糟糟的。這只是因?yàn)槲遗e得例子太小了省古。如果你寫你個(gè)大的系統(tǒng)粥庄,一開始你的這樣定義類的
public int age;
你的程序里大概有100處這樣的語句:
p.age = 10;
這個(gè)時(shí)候,突然要求你把數(shù)據(jù)類型變了衫樊,改成:
public String age;
你是不是要把那100處數(shù)據(jù)都加個(gè)雙引號呢飒赃?這是不是很麻煩?
如果你用了封裝科侈,你只需要這樣:
public void setAge(int age){
this.age = String.valueOf(age);
}
然后就搞定了载佳,是不是簡化了操作?
我只是舉個(gè)例子臀栈,實(shí)際開發(fā)中也不會出現(xiàn)改變數(shù)據(jù)類型這么操蛋的事蔫慧。。
封裝還有一個(gè)好處是模塊化权薯。當(dāng)你參與一個(gè)很多人實(shí)現(xiàn)的大型系統(tǒng)中姑躲,你不可能知道所有的類是怎樣實(shí)現(xiàn)的睡扬。你只需要知道這個(gè)類給我提供了哪些方法,我需要傳入什么數(shù)據(jù)黍析,我能得到什么結(jié)果卖怜。至于怎么得到的,關(guān)我x事阐枣?
所以說马靠,如果你寫的代碼還沒有用封裝,改過來吧蔼两。不是因?yàn)榇蠹叶加盟阅阋矐?yīng)該用甩鳄,而是這確實(shí)可以給你提供極大的便利。
結(jié)束~
有什么疑問或者錯(cuò)誤可以給我留言
下篇文章見~
轉(zhuǎn)載請注明出處6罨C羁小!?〈痢揖赴!
本文原創(chuàng)自csdn和簡書!品抽!
csdn地址:http://m.blog.csdn.net/article/details?id=53381737
簡書地址:http://www.reibang.com/p/9cc3a832fabb