閱讀926 返回首頁    go 阿裏雲 go 技術社區[雲棲]


連載:麵向對象葵花寶典:思想、技巧與實踐(11) - “封裝” 詳解

封裝的概念本身很好理解,意思就是把一堆東東裝起來。

 

但要想真正理解封裝,這樣還遠遠不夠。

第一個問題是:我們要封裝什麼?

這個問題很好回答,封裝當然是封裝不想讓別人知道或者看到的東東了。

例如:

你的身家。。。。。。

漂亮MM的年齡。。。。。。

富二代的女朋友數。。。。。

明星是否整過容。。。。。。

你是如何賺到100萬的(想想什麼樣的賺錢方法不想讓人知道?)。。。。。。

你是如何消磨時間的(想想什麼樣的消磨時間方法不想讓人知道?)。。。。。。

等等

站在麵向對象的角度來說,封裝就是“類”的一個功能,你可以封裝“類”的屬性(比如身家、年齡等),也可以封裝“類”的方法(比如說如何賺錢、如何消磨時間),也就是說,麵向對象通過“類”來實現了封裝。

  

第二個問題是:我們為什麼要封裝?

封裝數據的主要原因是保護隱私”,因為有“隱私”,所以要“封裝”。如果沒有封裝,你的隱私就暴露在所有人麵前了,別人也可以控製你的隱私,那樣將是非常危險的。

 

例如麵向過程的設計中,數據結構是公開的,任何能夠獲取到數據的人都可以隨意修改,也可以使用不同的方式修改,如果某個不小心的程序員或者菜鳥或者一個準備離職又心懷不滿的開發人員,無意或有意改錯了,那麼其它依賴這個數據的函數都會受到影響,要麼導致業務出錯,甚至導致程序崩潰。

 

而麵向對象的類封裝了屬性後,對屬性的修改隻能通過類的方法進行,一來不會暴露內部的具體屬性,二來對屬性的操作都是統一的,不會出現亂改的情況。

 

封裝方法的主要原因是“隔離複雜度。每個類隻需要關注自己的負責的功能如何完成即可,如果需要其它類配合,隻需要調用類的方法即可,而不需要了解其它類功能的具體的實現。

 

“隔離複雜度”的例子即使在現實世界中也比比皆是。例如我們夏天常用的空調能夠提供製冷功能,我們隻要輕輕一按遙控器的按鈕,空調就能夠開始製冷,但空調究竟是如何製冷的,絕大部分人並不知道,也並不關心。空調封裝了製冷的實現過程,對人提供了一個製冷的按鈕,人通過這個按鈕來啟動製冷的過程。

 

【封裝的樣例】

簡單的這麼回答你可能沒有什麼感覺,但給一個麵向對象“封裝”和麵向過程“無封裝”的例子,相信你就很清楚了。

 舉個簡單的例子,假設用程序實現付款這個操作,我們來看麵向對象和麵向過程的方式。

 

麵向過程 = 算法 + 數據結構

這裏的數據結構是公開的,每個地方都可以看到和引用的,而且必須知道,否則麵向過程的各個處理流程就沒法處理了。

具體代碼實現如下:

person.h

  1. #ifndef PERSON_H_  
  2. #define PERSON_H_  
  3.   
  4. typedef struct Person{  
  5.     char* name;  //姓名  
  6.     int money;   //金錢數量  
  7. }Person;  
  8.   
  9. #endif /* PERSON_H_ */  

money.c

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. #include "person.h"  
  5.   
  6. #define null 0x00  
  7.   
  8. int main(void) {  
  9.   
  10.     Person* me = (Person*)malloc(sizeof(Person));  
  11.     me->name = "華仔";  
  12.     me->money = 100;  
  13.   
  14.     //收銀員收銀  
  15.     if( me->money > 50 ){  
  16.         me->money -= 50;   //收銀操作時,需要知道Person實際有多少錢,然後直接操作Person的money  
  17.         printf("%s 付款成功,共  %d 塊\n", me->name, me->money);  
  18.     }  
  19.     else{  
  20.         printf("%s 付款失敗 \n", me->name);  
  21.     }  
  22.   
  23.     //小偷偷錢  
  24.     printf("偷了 %s %d 塊\n", me->name, me->money);  
  25.     me->money = 0;   //小偷也可以直接知道Person有多少錢,並直接操作Person的money  
  26.   
  27.     free(me);  
  28.     me = null;  
  29.     return EXIT_SUCCESS;  
  30. }  

也就是說,你有多少錢,所有人都知道!

也就是說,你的錢,別人可以隨便控製!

就像你去超市買東西,付款的時候,收銀員說:把你所有的錢擺在台子上,我從裏麵拿50.

不用我說你也知道,這當然是一件很恐怖的事情!

 

麵向對象 = 對象 + 交互

但在麵向對象的實現裏麵就不會這樣了,你不需要把錢擺出來,你隻需要拿出50就可以了,你既不需要擔心別人知道你有多少錢(然後實施某種後續動作),也不需要擔心別人拿錯了(不管是有意的還是無意的)。

 

具體實現代碼如下:

Person.java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.oo.java;  
  2.   
  3. /** 
  4.  * 普通人 
  5.  */  
  6. public class Person {  
  7.   
  8.     private String _name;    //姓名  
  9.     private Integer _money;  //金錢  
  10.       
  11.     public String getName() {  
  12.         return _name;  
  13.     }  
  14.   
  15.     public Boolean pay(Integer money){  
  16.         //付款的邏輯由Person自己控製,例如判斷當前的錢是否夠支付  
  17.         if( money > _money ){  
  18.               
  19.             return false;  
  20.         }  
  21.           
  22.         _money -= money;  
  23.         return true;  
  24.     }  
  25. }  

Cashier.java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.oo.java;  
  2.   
  3. /** 
  4.  * 收銀員 
  5.  */  
  6. public class Cashier {  
  7.   
  8.     public Boolean get(Person person, Integer money){  
  9.         Boolean result = person.pay(money);  //收銀員隻需要調用Person的pay方法,無需知道Person當前有多少錢  
  10.         if( result ){  
  11.             System.out.println(person.getName() + " 付款成功,共  " + money +" 塊");  
  12.         }  
  13.         else{  
  14.             System.out.println(person.getName() + " 付款失敗");  
  15.         }  
  16.           
  17.         return result;  
  18.     }  
  19. }  

Thief.java

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. package com.oo.java;  
  2.   
  3. /** 
  4.  * 小偷 
  5.  */  
  6. public class Thief {  
  7.   
  8.     public Boolean stole(Person person){  
  9.           
  10.         //小偷想直接訪問Person的money,但這樣做不允許,編譯出錯  
  11.         System.out.println("偷了 " + person.getName() +" " + person._money + " 塊\n");  
  12.         person._money = 0;  
  13.           
  14.         //雖然小偷這個類語法上也可以直接調用Person的pay方法,  
  15.         //但Person的pay方法裏麵可以做很多的校驗功能來讓這樣的調用返回失敗  
  16.         person.pay(50);  
  17.     }  
  18. }  

================================================ 
轉載請注明出處:https://blog.csdn.net/yunhua_lee/article/details/19611515
================================================ 

最後更新:2017-04-03 12:55:13

  上一篇:go 一樣的寒假不一樣的感受
  下一篇:go 深入淺出Java回調機製-(二)