第一篇:達內學習心得:精心總結的面向對象
達內學習心得:精心總結的面向對象
參賽學員:方錢有
獲獎獎項:二等獎
什么面向對象:
個人分析覺得:在程序設計里,面向對象是一種相對說法,相對于面向過程而言的;
面向“對象“:即重點在于“對象”;而面向過程:則重點在于“過程”,簡單說:就是我我們看待事物在眼光上注重點不一樣;比如說:我們評判一個女孩漂亮與否,有的人看重外表,有的人則看重“心靈”,只是側重點不一樣。
舉個例子:把大象裝進冰箱!
面向過程面向對象(注重一系列動作即過程)(注重動作所操作的承受者[“對象”])
“打開”冰箱“冰箱”打開“裝入”大象“大象”裝入“關閉”冰箱“冰箱”關閉
類:通俗的說類就是“一類事物的簡稱”,并且這些事物至少具有一點“共同的”特征.比如說:動物就是一個類
對象:就是某一類中一個具體的(就是可以具體描述出來的)東西,比如:動物(類)里的“狗”就是一個對象。(個人覺得對象相對于類而言的,因為狗又可以分好多種,‘狗’相對于‘哈士奇’是一個類,‘哈士奇’是‘狗’類的一個具體對象)
在生活中就拿描述汽車來說,我們都知道汽車都有4個輪子; 都有跑的功能 可以如下描述:
類汽車
屬性: 4個輪
功能: 跑
那么怎么在Java中描述汽車這類呢?
class car{
int wheel=4;//屬性: 4個輪
void run(){//方法(功能): 跑
System.out.println(“是汽車都會跑”);
}
}
那么可見“出租車”應當是“汽車”這類的一個具體化(實實在在的例子即“實例”)對象,那自然出租車也就具備了汽車這類所具備的“共有”屬性功能!
如何創建一個出租車對象呢?java中通過new關鍵字來創建一個類的實例即對象,也叫類的實例化,就是把類具體化成一個實例嘛!
格式:類名對象名 =mew 類名()
Cartexi =newCar();
創建了“出租車”對象(實例)之后那么它也就有了如下“自己”的屬性和功能。
int wheel=4;//屬性: 4個輪
void run(){//功能: 跑
System.out.println(“我是出租車我也會跑”);
}
我們如何來訪問對象中的它自己的屬性和方法呢?
格式:對象.屬性;對象.方法名();這一點也驗證了面向對象編程的側重點在于“對
象”上;
texi.wheel;texi.run()
*******************************************************************************
*******************************************************************************
*******************************************************************************
1.封裝:
從字面可以解讀為將東西封起來再裝好。要想拿到里面的東西就得有相應的方法打開,才能
拿到。
舉例來說:一個房間的門如果沒有上鎖,那么大家都可以進去拿東西,但現在我們不想讓誰
都進來拿東西,我們可以將房門上鎖,只對外提供一把鑰匙,只有有鑰匙的人才能進來,這
就是“封裝”現象!
在java程序中,“封裝”現象如何實現呢?
可以這樣實現:將類中的一些屬性和方法用private關鍵字修飾,將他們“私有化(即不對
外直接公開)”,使外部其他類不能通過創建該類對象或通過類名直接訪問這些屬性和方法;
只對外提供公有的方法,外部其他類必須通過該類對外提供的公有方法來訪問該類的相應成員;例如:
class Person{
private String name;//將name屬性私有化(封裝)[相當于了上鎖]使外部其他類不能直
接訪問到
public SetName(String name){//對外提供公有方法(相當于房門鑰匙)供外部其他類訪問
到本類屬性
this.name=name;
}
}
2.繼承:
從字面來說繼承就是子父類關系的簡稱,就是兒子(女兒也行,好吧)會繼承老爸的一些屬性和行為
在java中如何描述繼承關系呢?
注意:第一得知道在java中繼承是類與類之間或者是接口與接口之間才有繼承關系;
通過extends關鍵字來描述繼承關系
例如:老爸這個類
class Dad{
String sex=man;
void smoke(){
System.out.println(“老子會抽煙!”);
}
}
那么我們怎么來讓兒子這個類繼承老爸這個類呢?
class Son extends Dad{//通過extends關鍵字兒子這個類就繼承老爸這個類了
String name;//定義自己的屬性
String sex=man;//繼承過來的屬性,無須再定義,這里寫出來是為了好理解
void smoke(){//繼承過來的方法,無須再定義,這里寫出來是為了好理解
System.out.println(“老子會抽煙!”);
}
void playBall(){//定義自己的方法
System.out.println(“兒子即會打球又會抽煙!”);
}
void somke(){//重寫的方法
System.out.println(“我不抽20塊以下的煙”);
}
void smoke(int n){//重載的方法
System.out.println(“我抽了+n+”年的煙了“);
}
}
那么具有繼承關系的兩個類有什么特點呢?
1)子類會將父類的屬性和方法繼承過來,當然子類也可以自己定義的屬性和方法
2)當子類自己定義的方法和父類繼承過來的方法相同時會發生“重寫“現象!
3)父類用private關鍵字私有的方法是不能被繼承的!
4)子類可以使用super訪問父類的屬性和方法
5)子類通過重寫父類方法,修改父類的功能
6)子類構造器一定調用父類的無參構造器
7)構造器不能繼承
3.多態:
字面意思就是多種形態,也就是說一種事物同時局部多種形態.注意:要出現多態情況,那么類和類之間一定得是繼承關系,或者類和接口是實現關系
我覺得:在java中多態是相對于一個對象而言的,就是父類型引用變量引用子類對象,并
且父類型引用變量可以接受不同子類的對象
例如:拿上面的舉例
Dad uncle=new Son();父類引用變量uncle即具備Son類的成員又具備父類的成員;這也稱
為“向上造型”;
多態時的特點
1)多態時訪問成員變量,如uncle.name;
編譯時看等號左邊,父類有該成員變量則編譯通過,否則編譯出錯!
運行時也看等號左邊,有則運行結果
2)多態時訪問方法,如uncle.smoke()
編譯時看等號左邊,父類有該成員方法則編譯通過,否則編譯出錯!
運行時看等號右邊,父類有該方法,子類沒有該方法執行父類方法;父類有該方法,子類也
有該方法執行子類方法
3)多態時訪問靜態方法
編譯運行都看等號左邊
*******************************************************************************
*******************************************************************************
*******************************************************************************
*********************
4.抽象(有爭議):
什么是抽象?
抽象就是不具體。
一般我們把不能具體描述的東西約定俗成為“抽象”的東西。例如:我們說一個人長得很
“抽象”,n你想你能具體形容描述出來么?
在JAVA中如何描述抽象這個概念呢?
我覺得在java中抽象類是由抽象方法而衍生出來的,為什么呢?
因為Java規定一個類中定義了抽象方法那這個類就跟著必須定義為抽象類,而不是因
為先定義抽象類再跟著規定抽象類中的方法必須是抽象的,可能最后理解的結果是一樣的但
性質是不一樣的(個人理解)簡單說:就是有抽象方法的類一定是抽象類,但是抽象類中不
一定都是抽象方法,也可以有具體方法。
首先就是當我要在一個類定義一個方法時,暫時我不知道該方法具體功能是什么;等我想好
了我在用他實現一個功能時我再具體描述他功能,這樣我們就可以將這個方法用abstract關
鍵字修飾定義為抽象方法
(還有一點也就是什么時候定義抽象類的?也可以說抽象類是向上抽取而來的,就是幾個類
據有共同的屬性和方法,不想每個類都定義一次,那么定義一個公有類(即抽象類)其他類
只要繼承抽象類再重寫方法就行!)
例如:我有一百塊錢,現在我不知道怎么用,等我想好了在具體怎么用!
abstract class Money{//因為有了抽象方法所以必須定義為抽象類
public abstract void buySomthing();//現在不知道怎么用,那就把它的功能代碼體去掉
}
//現在我餓了,想買東西吃了,我就知道怎么用了
class Hungry extends Money{
void buySomething(){
System.out.println(”我餓了,現在我要買東西吃!“)
}
}
抽象類的特點
1)抽象類不能實例化
2)抽象類可以繼承抽象類
3)繼承抽象類必須得重寫抽象方法
5.抽象類,接口,普通類 的不同點和相同點?
1)不同點:
普通類接口抽象類
可以直接實例化對象不可以直接實例化對象不可以直接實例化對象
可以定義任何成員只能定義抽象成員方法和常量成員
方法必須定義為抽象其他和普通類相同
可以被繼承類可以實現接口,且可以實現多個接口可以被繼承
接口可以繼承多個接口抽象類有構造方
法,接口中不能有
抽象類有普通成員變
量,接口中沒有
抽象類可以有非抽象方
法,接口中不能有
抽象類可以用public、protected修飾,接口中只能public(默認public)
抽象類包含靜態方法,接
口中沒有
接口中的變量只能是
public static final,抽象類中可以是任意類型修飾
2)相同點:都可以用于描述(封裝)事物的,內部類分為哪幾種?分別如何創建對象?
分為 局部內部類,匿名內部類...3種
1)外部類名.內部類名 對象名=new 外部類名().new 內部類名()
2)外部類名.內部類名 對象名=外部類名.new 內部類名()
3)....不記得了第3種
匿名內部類
二、集合集合的定義?
集合:用來保存一組數據的數據結構
集合的父接口,實現接口,實現類,實現類的常用方法是什么?(建議以樹狀圖畫出來,便
于加深印象)。
Collectionlistset
ArraylistLinkedListHashSet
TreeSet
1.List集合List集合的特征是元素可重復且有序 ;我們可以把他看成是一個動態數組,一般通過下標
訪問
ArrayList和LinkedList最常用的兩個子類實現
1)list可以使用for循環遍歷
for(int i=;i list.get(i); } 2)list的淺層復制 調用ArraryList.clone()方法 注意:不能使用list.clone(),clone()方法是Object類的方法,list是接口是不能繼承Object類的2.Set集合: 不重復且無序集 遍歷set只能迭代器,用迭代器遍歷集合遵循的操作原則:先問后取。問一次取一次。Iterator while(it.hashnext()){ E e=it.next(); } 3)map表 Map存儲數據使用key-value(鍵-值)對的形式存儲數據的。 對于Map而言,要求key值是唯一的。value值可以重復 獲取數據時,使用key可以獲取其對應的value 遍歷map有3種方法 1)遍歷key Set for(String key:keySet){ System.out.println(”key:“ + key); //可以根據每一個key獲取其對應的value值 int value = map.get(key); 2)遍歷value Collection Iterator while(it.hasNext()){ int value = it.next();//不能采用 map.next() System.out.println(”value:“ + value); 注意:通過迭代器在遍歷集合的過程中,不能通過集合(即不能采用 map.next())去改變集合元素數量 3)遍歷鍵值對 Set for(Entry //獲取一組鍵值對的鍵和值 String key = entry.getKey(); int value = entry.getValue(); System.out.println(key + ”=" + value); Collection接口方法的定義 這里我主要列舉 Iterator iterator()方法的使用 Collection提供的方法 Iterator iterator()方法來獲取迭代器 Iterator是一個接口,定義了遍歷集合應有的方法。 使用迭代器遍歷集合遵循的操作原則:先問后取。問一次取一次。問:boolean hashNext() 取:Object next() 迭代器可以將取出的數據刪除掉 刪:remove()將當前獲取的元素刪除掉。 注意:1)刪除的是next()取出的元素。且只能刪除一次! 2)調用1次next()后只能調用一次remove()! 達內學習心得:精心總結的面向對象 參賽學員:方錢有 獲獎獎項:二等獎 什么面向對象: 個人分析覺得:在程序設計里,面向對象是一種相對說法,相對于面向過程而言的; 面向“對象“:即重點在于“對象”;而面向過程:則重點在于“過程”,簡單說:就是我我們看待事物在眼光上注重點不一樣;比如說:我們評判一個女孩漂亮與否,有的人看重外表,有的人則看重“心靈”,只是側重點不一樣。舉個例子:把大象裝進冰箱! 面向過程 面向對象 (注重一系列動作即過程) (注重動作所操作的承受者[“對象”]) “打開”冰箱 “冰箱”打開 “裝入”大象 “大象”裝入 “關閉”冰箱 “冰箱”關閉 類:通俗的說類就是“一類事物的簡稱”,并且這些事物至少具有一點“共同的”特征.比如說:動物就是一個類 對象:就是某一類中一個具體的(就是可以具體描述出來的)東西,比如:動物(類)里的“狗”就是一個對象。(個人覺得對象相對于類而言的,因為狗又可以分好多種,‘狗’相對于‘哈士奇’是一個類,‘哈士奇’是‘狗’類的一個具體對象) 在生活中就拿描述汽車來說,我們都知道汽車都有4個輪子; 都有跑的功能 可以如下描述: 類 汽車 屬性: 4個輪 功能: 跑 那么怎么在Java中描述汽車這類呢? class car{ int wheel=4;//屬性: 4個輪 void run(){//方法(功能): 跑 System.out.println(“是汽車都會跑”); } } 那么可見“出租車”應當是“汽車”這類的一個具體化(實實在在的例子即“實例”)對象,那自然出租車也就具備了汽車這類所具備的“共有”屬性功能! 如何創建一個出租車對象呢?java中通過new關鍵字來創建一個類的實例即對象,也叫類的實例化,就是把類具體化成一個實例嘛!格式:類名 對象名 = mew 類名 () Car texi = new Car();創建了“出租車”對象(實例)之后那么它也就有了如下“自己”的屬性和功能。 int wheel=4;//屬性: 4個輪 void run(){//功能: 跑 System.out.println(“我是出租車我也會跑”); } 我們如何來訪問對象中的它自己的屬性和方法呢? 格式:對象.屬性; 對象.方法名(); 這一點也驗證了面向對象編程的側重點在于“對象”上; texi.wheel; texi.run()********************************************************************************************************************************************************************************************************************************************* 1.封裝: 從字面可以解讀為將東西封起來再裝好。要想拿到里面的東西就得有相應的方法打開,才能拿到。 舉例來說:一個房間的門如果沒有上鎖,那么大家都可以進去拿東西,但現在我們不想讓誰都進來拿東西,我們可以將房門上鎖,只對外提供一把鑰匙,只有有鑰匙的人才能進來,這就是“封裝”現象! 在java程序中,“封裝”現象如何實現呢? 可以這樣實現:將類中的一些屬性和方法用private關鍵字修飾,將他們“私有化(即不對外直接公開)”,使外部其他類不能通過創建該類對象或通過類名直接訪問這些屬性和方法;只對外提供公有的方法,外部其他類必須通過該類對外提供的公有方法來訪問該類的相應成員;例如: class Person{ private String name;//將name屬性私有化(封裝)[相當于了上鎖]使外部其他類不能直接訪問到 public SetName(String name){//對外提供公有方法(相當于房門鑰匙)供外部其他類訪問到本類屬性 this.name=name; } } 2.繼承: 從字面來說繼承就是子父類關系的簡稱,就是兒子(女兒也行,好吧)會繼承老爸的一些屬性和行為 在java中如何描述繼承關系呢? 注意: 第一得知道在java中繼承是類與類之間或者是接口與接口之間才有繼承關系;通過extends關鍵字來描述繼承關系 例如:老爸這個類 class Dad{ String sex=man; void smoke(){ System.out.println(“老子會抽煙!”); } } 那么我們怎么來讓兒子這個類繼承老爸這個類呢? class Son extends Dad{//通過extends關鍵字兒子這個類就繼承老爸這個類了 String name;//定義自己的屬性 String sex=man;//繼承過來的屬性,無須再定義,這里寫出來是為了好理解 void smoke(){//繼承過來的方法,無須再定義,這里寫出來是為了好理解 System.out.println(“老子會抽煙!”); } void playBall(){//定義自己的方法 System.out.println(“兒子即會打球又會抽煙!”); } void somke(){//重寫的方法 System.out.println(“我不抽20塊以下的煙”); } void smoke(int n){//重載的方法 System.out.println(“我抽了+n+”年的煙了“); } } 那么具有繼承關系的兩個類有什么特點呢? 1)子類會將父類的屬性和方法繼承過來,當然子類也可以自己定義的屬性和方法 2)當子類自己定義的方法和父類繼承過來的方法相同時會發生“重寫“現象!3)父類用private關鍵字私有的方法是不能被繼承的!4)子類可以使用super訪問父類的屬性和方法 5)子類通過重寫父類方法,修改父類的功能 6)子類構造器一定調用父類的無參構造器 7)構造器不能繼承 3.多態: 字面意思就是多種形態,也就是說一種事物同時局部多種形態.注意:要出現多態情況,那么類和類之間一定得是繼承關系,或者類和接口是實現關系 我覺得:在java中多態是相對于一個對象而言的,就是父類型引用變量引用子類對象,并且父類型引用變量可以接受不同子類的對象 例如:拿上面的舉例 Dad uncle=new Son();父類引用變量uncle即具備Son類的成員又具備父類的成員;這也稱為“向上造型”; 多態時的特點 1)多態時訪問成員變量,如uncle.name;編譯時看等號左邊,父類有該成員變量則編譯通過,否則編譯出錯!運行時也看等號左邊,有則運行結果 2)多態時訪問方法,如uncle.smoke()編譯時看等號左邊,父類有該成員方法則編譯通過,否則編譯出錯!運行時看等號右邊,父類有該方法,子類沒有該方法執行父類方法;父類有該方法,子類也有該方法執行子類方法 3)多態時訪問靜態方法 編譯運行都看等號左邊 ****************************************************************************************************************************************************************************************************************************************************************** 4.抽象(有爭議): 什么是抽象? 抽象就是不具體。 一般我們把不能具體描述的東西約定俗成為“抽象”的東西。例如:我們說一個人長得很“抽象”,n你想你能具體形容描述出來么? 在JAVA中如何描述抽象這個概念呢? 我覺得在java中抽象類是由抽象方法而衍生出來的,為什么呢? 因為Java規定一個類中定義了抽象方法那這個類就跟著必須定義為抽象類,而不是因為先定義抽象類再跟著規定抽象類中的方法必須是抽象的,可能最后理解的結果是一樣的但性質是不一樣的(個人理解)簡單說:就是有抽象方法的類一定是抽象類,但是抽象類中不一定都是抽象方法,也可以有具體方法。首先就是當我要在一個類定義一個方法時,暫時我不知道該方法具體功能是什么;等我想好了我在用他實現一個功能時我再具體描述他功能,這樣我們就可以將這個方法用abstract關鍵字修飾定義為抽象方法 (還有一點也就是什么時候定義抽象類的?也可以說抽象類是向上抽取而來的,就是幾個類據有共同的屬性和方法,不想每個類都定義一次,那么定義一個公有類(即抽象類)其他類只要繼承抽象類再重寫方法就行!) 例如:我有一百塊錢,現在我不知道怎么用,等我想好了在具體怎么用!abstract class Money{//因為有了抽象方法所以必須定義為抽象類 public abstract void buySomthing();//現在不知道怎么用,那就把它的功能代碼體去掉 } //現在我餓了,想買東西吃了,我就知道怎么用了 class Hungry extends Money{ void buySomething(){ System.out.println(”我餓了,現在我要買東西吃!“) } } 抽象類的特點 1)抽象類不能實例化 2)抽象類可以繼承抽象類 3)繼承抽象類必須得重寫抽象方法 5.抽象類,接口,普通類 的不同點和相同點? 1)不同點: 普通類 接口 抽象類 可以直接實例化對象 不可以直接實例化對象 不可以直接實例化對象 可以定義任何成員 只能定義抽象成員方法和常量 成員方法必須定義為抽象其他和普通類相同 可以被繼承 類可以實現接口,且可以實現多個接口 可以被繼承 接口可以繼承多個接口 抽象類有構造方法,接口中不能有 抽象類有普通成員變量,接口中沒有 抽象類可以有非抽象方法,接口中不能有 抽象類可以用public、protected修飾,接口中只能public(默認public) 抽象類包含靜態方法,接口中沒有 接口中的變量只能是public static final,抽象類中可以是任意類型修飾 2)相同點:都可以用于描述(封裝)事物的,內部類分為哪幾種?分別如何創建對象? 分為 局部內部類,匿名內部類...3種 1)外部類名.內部類名 對象名=new 外部類名().new 內部類名()2)外部類名.內部類名 對象名=外部類名.new 內部類名()3)....不記得了第3種 匿名內部類 二、集合集合的定義? 集合:用來保存一組數據的數據結構 集合的父接口,實現接口,實現類,實現類的常用方法是什么?(建議以樹狀圖畫出來,便于加深印象)。 Collection list set Arraylist LinkedList HashSet TreeSet 1.List集合 List集合的特征是元素可重復且有序 ;我們可以把他看成是一個動態數組,一般通過下標訪問 ArrayList和LinkedList最常用的兩個子類實現 1)list可以使用for循環遍歷 for(int i=;i list.get(i);} 2)list的淺層復制 調用ArraryList.clone()方法 注意:不能使用list.clone(),clone()方法是Object類的方法,list是接口是不能繼承Object類的 2.Set集合: 不重復且無序集 遍歷set只能迭代器,用迭代器遍歷集合遵循的操作原則:先問后取。問一次取一次。Iterator E e=it.next();} 3)map表 Map存儲數據使用key-value(鍵-值)對的形式存儲數據的。 對于Map而言,要求key值是唯一的。value值可以重復 獲取數據時,使用key可以獲取其對應的value 遍歷map有3種方法 1)遍歷key Set for(String key:keySet){ System.out.println(”key:“ + key); //可以根據每一個key獲取其對應的value值 int value = map.get(key);2)遍歷value Collection Iterator while(it.hasNext()){ int value = it.next();//不能采用 map.next() System.out.println(”value:“ + value);注意:通過迭代器在遍歷集合的過程中,不能通過集合(即不能采用 map.next())去改變集合元素數量 3)遍歷鍵值對 Set for(Entry //獲取一組鍵值對的鍵和值 String key = entry.getKey(); int value = entry.getValue(); System.out.println(key + ”=" + value); Collection接口方法的定義 這里我主要列舉 Iterator iterator()方法的使用 Collection提供的方法 Iterator iterator()方法來獲取迭代器 Iterator是一個接口,定義了遍歷集合應有的方法。 使用迭代器遍歷集合遵循的操作原則:先問后取。問一次取一次。 問:boolean hashNext() 取:Object next() 迭代器可以將取出的數據刪除掉 刪:remove()將當前獲取的元素刪除掉。 注意:1)刪除的是next()取出的元素。且只能刪除一次! 2)調用1次next()后只能調用一次remove()! 面向對象課程學習心得 這學期的面向對象課程對我來說是收獲匪淺的一門課。通過老師課件的講解,自己一些相關書籍的閱讀和實踐作業的完成,逐步對課程有了由淺及深的認識。 面向對象(Object Oriented,OO)是一門以實踐為主課程,課程中可以分開兩塊OOA(面向對象系統分析)和OOD(面向對象系統設計)。OOA(面向對象系統分析)主要內容: 研究問題域和用戶需求,運用面向對象的觀點和原則發現問題域中與系統責任有關的對象,以及對象的特征和相互關系.OOA不涉及針對具體實現采取的設計決策和有關細節,獨立于具體實現的系統模型。是一個完整確切反映問題域和用戶需求的系統模型。OOA的優勢:復用、可擴展、可維護性、彈性。 OOD(面向對象系統設計):以OOA模型為基礎,按照實現的要求進行設計決策,包括全局性的決策和局部細節的設計,與具體的實現條件相關。OOD的步驟:細化重組類→細化和實現類之間的關系,明確其可見性→增加屬性,指定屬性的類型和可見性→分配職責,定義執行每個職責的方法→對消息驅動的系統,明確消息傳遞的方式→利用設計模式進行局部設計→畫出詳細的類圖和時序圖。 面向對象的分析與設計方法將致力于解決傳統軟件研發過程中由于軟件模塊化結構化程度不高帶來的軟件重用性差、軟件可維護性差、開發出的軟件不能滿足用戶需要等方面問題。面向對象的概念包括:對象、對象的狀態和行為、類、類的結構、消息和方法。對象概念將包含對象唯一性、抽象性、繼承性、多態性的重要特征。面向對象的要素包含:抽象、封裝性、共享性三方面。 在設計模式的研究過程中,我們組選擇的是迭代器(Iterator)的設計模式研究。完成設計研究后,我對迭代器的設計模式有了更為深刻的理解。迭代器(Iterator)提供一個方法順序訪問一個聚合對象的各個元素,而又不暴露該對象的內部表示。并了解到迭代器設計模式一般在以下三類場合使用較多。 ? 訪問一個聚合對象的內容而無需暴露它的內部表示。? 支持對聚合對象的多種遍歷。因為遍歷狀態是保存在每一個迭代器對象中的。 ? 為遍歷不同的聚合結構提供一個統一的接口。根據實現方式的不同,效果上會有差別。同時還簡化了容器的接口。但是在java Collection中為了提高可擴展性,容器還是提供了遍歷的接口。在面向對象的軟件設計中,我們經常會遇到一類集合對象,這類集合對象的內部結構可能有著各種各樣的實現,但是歸結起來,無非有兩點是需要我們去關心的:一是集合內部的數據存儲結構,二是遍歷集合內部的數據。面向對象設計原則中有一條是類的單一職責原則,所以我們要盡可能的去分解這些職責,用不同的類去承擔不同的職責。Iterator模式就是分離了集合對象的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部代碼透明的訪問集合內部的數據。 在Java Collection的應用中,提供的具體迭代器角色是定義在容器角色中的內部類。這樣便保護了容器的封裝。但是同時容器也提供了遍歷算法接口,你可以擴展自己的迭代器。至于迭代器模式的使用。客戶程序要先得到具體容器角色,然后再通過具體容器角色得到具體迭代器角色。這樣便可以使用具體迭代器角色來遍歷容器了。 OOA和OOD之間沒有明顯的界限。OOA與OOD的不可分割性正好說明了OO思想的強大,即軟件過程階段的無縫連接,在交流與溝通中不會產生鴻溝,這是相對結構化思想的好處,因為從功能模塊到某塊詳細控制邏輯設計兩者之間的聯系不是十分緊密,需要分析人員與設計人員的再溝通。 通過課程的學習與實踐,對面向對象的理念,以及相關方法,設計模式有了更為深刻的理解與掌握。針對面向對象的分析與設計課程的授課內容及方法,我個人覺得對我還是有不少的幫助和 提高。結合自己的工作,雖然與開發接觸的比較少,但是在運維過程中,如果能了解開發原理,結合實際的工作,會對一些源代碼的分析能力以及工作效率的提高起到明顯的幫助作用。 一、封裝 這是一種隱藏信息的特性。拿本節引例來說,類CalculateDate 將數據結構與算法隱藏在類的內部,外界使用者無需知道具體技術實現細節即可使用此類。封裝這一特性不僅大大提高了代碼的易用性,而且還使得類的開發者可以方便地更換新的算法,這種變化不會影響使用類的外部代碼。可以用以下公式展示類的封裝特性:封裝的類=數據+對此數據所進行的操作(即算法)。通俗地說,封裝就是:包起外界不必需要知道的東西,只向外界展露可供展示的東西。在面向對象理論中,封裝這個概念擁有更為寬廣的含義。小到一個簡單的數據結構,大到一個完整的軟件子系統,靜態的如某軟件系統要收集數據信息項,動態的如某個工作處理流程,都可以封裝到一個類中。具備這種“封裝”的意識,是掌握面向對象分析與設計技巧的關鍵。 二、繼承 繼承是面向對象編程中一個非常重要的特性,它也是另一個重要特性——多態的基礎。現實生活中的事物都歸屬于一定的類別。在一些書中,將父類稱為超類(super class)。“繼承”關系有時又稱為“派生”關系,“B 繼承自A”,可以說為“B 派生自A”,或反過來說,“A 派生出B”。父類與子類之間擁有以下兩個基本特性: (1)是一種(IS-A)關系:子類是父類的一種特例。 (2)擴充(Extends)關系:子類擁有父類所沒有的功能。 1.類成員的訪問權限 面向對象編程的一大特點就是可以控制類成員的可訪問性。當前主流的面向對象語言都擁有以下三種基本的可訪問性: (1)公有 public 訪問不受限制。 (2)私有 private 只有類自身成員可以訪問。 (3)保護 protected 子類可以訪問,其他類無法訪問。 由此可見,可以通過子類對象訪問其父類的所有公有成員,事實上,外界根本分不清楚對象的哪些公有成員來自父類,哪些公有成員來自子類自身。小結一下繼承條件下的類成員訪問權限: (1)所有不必讓外人知道的東西都是私有的。 (2)所有需要向外提供的服務都是公有的。 (3)所有的“祖傳絕招”,“秘不外傳”的都是保護的。 C#中還有一種可訪問性,就是由關鍵字internal 所確定的“內部”訪問性。internal 有點像public,外界類也可以直接訪問聲明為internal 的類或類的成員,但這只局限于同一個程序集內部。 讀者可以簡單地將程序集理解為一個獨立的DLL 或EXE 文件。一個DLL 或EXE 文件中可以有多個類,如果某個類可被同一程序集中的類訪問,但其他程序集中的類不能訪問它,則稱此類具有internal 訪問性。internal 是C#的默認可訪問性,這就是說,如果某個類沒有任何可訪問性關鍵字在它前面,則它就是internal 的。 2.子類父類變量的相互賦值 子類對象可以被當成基類對象使用。這是因為子類對象本就是一種(IS_A)父類對象,因此,以下代碼是合法的: Parent p; Son c = new Son(); p = c; 然而,反過來就不可以,父類對象變量不可以直接賦值給子類變量。如果確信父類變量中所引用的對象的確是子類類型,則可以通過類型強制轉換進行賦值,其語法格式為: 子類對象變量=(子類名稱)基類對象變量; 子類對象變量=基類對象變量 as 子類名稱; 3.方法重載、隱藏與虛方法調用 由于子類對象同時匯集了父類和子類的所有公共方法,而C#并未對子類和父類的方法名稱進行過多限制,因此,一個問題出現了:如果子類中某個方法與父類方法的簽名一樣(即方法名和方法參數都一樣),那當通過子類對象訪問此方法時,訪問的是子類還是父類所定義的方法?讓我們先從子類方法與父類方法之間的關系說起。總的來說,子類方法與父類方法之間的關系可以概括為以下三種: (1)擴充(Extend):子類方法,父類沒有; (2)重載(Overload):子類有父類的同名函數,但參數類型或數目不一樣; (3)完全相同:子類方法與父類方法從方法名稱到參數類型完全一樣。 當子類與父類擁有完全一樣的方法時,稱“子類隱藏了父類的同名方法,當分別位于父類和子類的兩個方法完全一樣時,調用哪個方法由對象變量的類型決定。“new”關鍵字明確告訴C#編譯器,子類隱藏父類的同名方法,提供自己的新版本。如果子類隱藏了父類的同名方法,要在子類方法的實現代碼中調用父類被隱藏的同名方法時要使用base 關鍵字。如果子類隱藏了父類的同名方法,不進行強制轉換,就無法通過父類變量直接調用子類的同名方法,哪怕父類變量引用的是子類對象。這是不太合理的。我們希望每個對象都只干自己職責之內的事,即如果父類變量引用的是子類對象,則調用的就是子類定義的方法,而如果父類變量引用的就是父類對象,則調用的是父類定義的方法。這就是說,希望每個對象都“各人自掃門前雪,莫管他人瓦上霜”。為達到這個目的,可以在父類同名方法前加關鍵字virtual,表明這是一個虛方法,子類可以重寫此方法:即在子類同名方法前加關鍵字override,表明對父類同名方法進行了重寫。所以,將父類方法定義為虛方法,子類重寫同名方法之后,通過父類變量調用此方法,到底是調用父類還是子類的,由父類變量引用的真實對象類型決定,而與父類變量無關!很明顯,“虛方法調用”特性可以讓我們寫出非常靈活的代碼,大大減少由于系統功能 擴充和改變所帶來的大量代碼修改工作量。由此給出結論:面向對象語言擁有的“虛方法調用”特性,使我們可以只用同樣的一個語句,在運行時根據對象類型而執行不同的操作。 三、抽象 1.抽象類與抽象方法 在一個類前面加上“abstract”關鍵字,此類就成為了抽象類。對應地,一個方法類前面加上“abstract”關鍵字,此方法就成為了抽象方法。注意抽象方法不能有實現代碼,在函數名后直接跟一個分號。抽象類專用于派生出子類,子類必須實現抽象類所聲明的抽象方法,否則,子類仍是抽象類。抽象類一般用于表達一種比較抽象的事物,而抽象方法則說明此抽象類應該具有的某種性質,從同一抽象類中繼承的子類擁有相同的方法(即抽象類所定義的抽象方法),但這些方法的具體代碼每個類都可以不一樣。抽象類不能創建對象,一般用 它來引用子類對象。一個抽象類中可以包含非抽象的方法和字段。因此:包含抽象方法的類一定是抽象類,但抽象類中的方法不一定是抽象方法。除了方法可以是抽象的之外,屬性也可以是抽象的。 2.接口 接口可以看成是一種“純”的抽象類,它的所有方法都是抽象方法。抽象類定義了對象所屬的類別,而接口實際上定義了一種對象應具有的行為特性。某個類可以實現多個接口,當創建一個此類的對象之后,通過引用這個對象的對象變量可以訪問其所有的公有方法(包括自身的公有方法以及由接口定義的公有方法以)。在這種情況下,根本分不清哪些方法是由接口定義的,哪些是由類自己定義的。C#提供了一種“顯式接口”實現機制,可以區分開這兩種情況。由此得到一個結論:如果一個類顯式實現某個接口,則只能以此接口類型的變量為媒介調用此接口所定義的方法,而不允許通過類的對象變量直接調用。或者這樣說:被顯式實現的接口方法只能通過接口實例訪問,而不能通過類實例直接訪問。 四、多態 方法重載屬于多態的一種,兩個構成重載關系的函數必須滿足幾個條件:函數名相同、參數類型不同,或參數個數不同。具體調用哪個方法要看參數,需要注意的是,方法返回值類型的不同不是方法重載的判斷條件。多態編程的基本原理是:使用基類或接口變量編程。在多態編程中,基類一般都是抽象基類,其中擁有一個或多個抽象方法,各個子類可以根據需要重寫這些方法。或者使用接口,每個接口都規定了一個或多個抽象方法,實現接口的類根據需要實現這些方法。因此,多態的實現分為兩大基本類別:繼承多態和接口多態。 1.接口多態與繼承多態 接口多態與繼承多態其編程方式與作用都是類似的。但由于一個類可以實現多個接口,所以,接口多態較繼承多態更靈活,因而在編程中也用得更廣。多態是面向對象技術中最精華的部分之一。大量的精巧軟件設計方案都建立在對多態特性的巧妙應用上。在編程中應用多態,可以將其簡化為兩句:應用繼承實現對象的統一管理;應用接口定義對象的行為特性。對比傳統的不使用多態的編程方式,使用多態的好處是:當要修改程序并擴充系統時,需要修改的地方較少,對其他部分代碼的影響較小。 五、類與對象 類是面向對象編程的基本單元,與使用C語言等結構化編程語言不一樣,使用C#編程,所有的程序代碼幾乎都放在類中,不存在獨立于類之外的函數。一個類可以包含兩種成員:靜態成員和實例成員,靜態成員是供類的所有對象所共享的,而實例成員只供某一個對象所有。實例成員與靜態成員的訪問規則:位于同一類中的實例方法可直接相互調用;類的字段(包括實例字段和靜態字段)可以被同一類中的所有實例方法直接訪問;類中的靜態方法只能直接訪問類靜態字段。 類中包括:方法和字段,屬性是一種特殊的字段,它可以保證數據的合法性,方法和字段這兩個概念是面向對象理論的術語,是通用于各種面向對象語言的。字段(Field)代表了類中的數據,在類的所有方法之外定義一個變量即定義了一個字段。在變量之前可以加上public、private 和protected 表示字段的訪問權限。方法(function)功能代碼的集合,在程序開發過程中,經常發現多處需要實現或調用某一個公用功能,這些功能的實現都需要書 寫若干行代碼。如果在調用此功能的地方重復書寫這些功能代碼,將會使整個程序中代碼大量重復,會增大開發工作量,增加代碼維護的難度。為了解決代碼重復的問題,絕大多數程序設計語言都將完成某一公用功能的多個語句組合在一起,起一個名字用于代表這些語句的全體,這樣的代碼塊被稱為“函數(function)”。引入“函數”概念之后,程序中凡需要調用此公用功能的地方都可以只寫出函數名,此名字就代表了函數中所包含的所有代碼,這樣一來,就不再需要在多個地方重復書寫這些功能代碼。 對象是以類為模板創建出來的。類與對象之間是一對多的關系。在C#中,使用new 關鍵字創建對象。在程序中“活躍”的是對象而不是類。在面向對象領域,對象有時又被稱為是“類的實例”,“對象”與“類的實例”這兩個概念是等同的。 六、值類型與引用類型 1.值類型 值類型變量與引用類型變量的內存分配模型也不一樣。每個正在運行的程序都對應著一個進程(process),在一個進程內部,可以有一個或多個線程(thread),每個線程都擁有一塊“自留地”,稱為“線程堆棧”,大小為1M,用于保存自身的一些數據,比如函數中定義的局部變量、函數調用時傳送的參數值等,這部分內存區域的分配與回收不需要程序員干涉。所有值類型的變量都是在線程堆棧中分配的。值類型共有三種:簡單類型、枚舉類型和結構類型。 2.引用類型 另一塊內存區域稱為“堆(heap)”,在.NET 這種托管環境下,堆由CLR 進行管理,所以又稱為“托管堆(managed heap)”。用new 關鍵字創建的類的對象時,分配給對象的內存單元就位于托管堆中。在程序中我們可以隨意地使用new 關鍵字創建多個對象,因此,托管堆中的內存資源是可以動態申請并使用的,當然用完了必須歸還。打個比方更易理解:托管堆相當于一個旅館,其中的房間相當于托管堆中所擁有的內存單元。當程序員用new 方法創建對象時,相當于游客向旅館預訂房間,旅館管理員會先看一下有沒有合適的空房間,有的話,就可以將此房間提供給游客住宿。當游客旅途結束,要辦理退房手續,房間又可以為其他旅客提供服務了。引用類型共有四種:類類型、接口類型、數組類型和委托類型。所有引用類型變量所引用的對象,其內存都是在托管堆中分配的。嚴格地說,我們常說的“對象變量”其實是類類型的引用變量。但在實際中人們經常將引用類型的變量簡稱為“對象變量”,用它來指代所有四種類型的引用變量。 七、命名空間與類庫 1.命名空間 在使用面向對象技術開發的現代軟件系統中,經常擁有數百甚至上千個類,為了方便地管理這些類,面向對象技術引入了“命名空間(namespace)”的概念。命名空間可以看成是類的“容器”,它可以包含多個類。.NET Framework 使用命名空間來管理所有的類。如果把類比喻成書的話,則命名空間類似于放書的書架,書放在書架上,類放在命名空間里。當我們去圖書館查找一本書時,需要指定這本書的編號,編號往往規定了書放在哪個書庫的哪個書架上,通過逐漸縮小的范圍:圖書館->書庫->書架,最終可以在某個書架中找到這本書。類似地,可以采用圖書館保存圖書類似的方法來管理類,通過逐漸縮小的范圍:最大的命名空間->子命名空間->孫命名空間??,最終找到一個類。 2.類庫 為了提高軟件開發的效率,人們在整個軟件開發過程中大量應用了軟件工程的模塊化原則,將可以在多個項目中使用的代碼封裝為可重用的軟件模塊,其于這些可復用的軟件模塊,再開發新項目就成為“重用已有模塊,再開發部分新模塊,最后將新舊模塊組裝起來”的過程。整個軟件開發過程類似于現代工業的生產流水線,生產線上的每個環節都由特定的人員負責,整個生產線上的工作人員既分工明確又相互合作,大大地提高了生產效率。在組件化開發大行其道的今天,人們通常將可以重用的軟件模塊稱為“軟件組件”。在全面向對象的.NET 軟件平臺之上,軟件組件的表現形式為程序集(Assembly),可以通過在Visual Studio 中創建并編譯一個類庫項目得到一個程序集。在Visual Studio 的項目模板中,可以很方便地創建類庫(Class Library)項目,Visual Studio 會自動在項目中添加一個名為Class1.cs 的類文件,程序員可在此類文件中書寫代碼,或者添加新的類。一個類庫項目中可以容納的類數目沒有限制,但只有聲明為public 的類可以被外界使用。類庫項目編譯之后,會生成一個動態鏈接庫(DLL:Dynamic Link Library)文件。這就是可以被重用的.NET 軟件組件——程序集。默認情況下,類庫文件名就是項目名加上“.dll”后綴。每個類庫項目都擁有一個默認的命名空間,可以通過類庫項目的屬性窗口來指定。需要仔細區分“類庫項目”、“程序集”和“命名空間”這三個概念的區別: (1)每個類庫項目編譯之后,將會生成一個程序集。 (2)類庫項目中可以擁有多個類,這些類可屬于不同的命名空間。 (3)不同的類庫項目可以定義相同的命名空間。 根據上述三個特性,可以得到以下結論:“命名空間”是一個邏輯上的概念,它的物理載體是“程序集”,具體體現為“DLL”(或EXE)文件。在Visual Studio 中,可通過創建“類庫”類型的項目生成程序集。一個程序集可以有多個命名空間,而一個命名空間也可以分布于多個程序集。一旦生成了一個程序集,在其他項目中就可以通過添加對這一程序集的引用而使用此程序集中的類。其方法是在“項目”菜單中選擇“添加程序集”命令,激活“瀏覽”卡片,選擇一個現有的程序集文件(DLL 或EXE)。一個項目添加完對特定程序集的引用之后,就可以直接創建此程序集中的類了,當然要注意指明其命名空間。 八、委托 委托是一種新的面向對象語言特性,在歷史比較長的面向對象語言比如C++中并未出現過。微軟公司在設計運行于.NET Framework平臺之上的面向對象語言(如C#和VisualBasic.NET)時引入了這一新特性。委托(delegate)也可以看成是一種數據類型,可以用于定義變量。但它是一種特殊的數據類型,它所定義的變量能接收的數值只能是一個函數,更確切地說,委托類型的變量可以接收一個函數的地址,很類似于C++語言的函數指針。簡單地說:委托變量可看成是一種類型安全的函數指針,它只能接收符合其要求的函數地址。委托可以看成是一個函數的“容器”,將某一具體的函數“裝入”后,就可以把它當成函數一樣使用。定義委托類型時對函數的要求被稱為函數的“簽名(signature)”。函數的簽名規定了函數的參數數目和類型,以及函數的返回值,體現了函數的本質特征。每一個委托都確定了一個函數的簽名。擁有不同簽名的函數不能賦值給同一類型的委托變量。因此,一個委托類型的變量,可以引用任何一個滿足其要求的函數。 1.委托的組合與分解 委托變量可以代表某一函數,使用委托變量就相當于調用一個函數。如果僅是這么簡單,那么直接調用函數不就行了嗎?為什么還要引入“委托”這一特性?事實上,委托不僅可以代表一個函數,還可以組合“一堆”的函數,然后批量執行它們,這樣的委托變量又稱為“多路委托變量”。可以用加法運算符來組合單個委托變量為多路委托變量。類似地,也可以使用減法運算符來從一個多路委托變量中移除某個委托變量。 2.事件與多路委托 事件的主要特點是一對多關聯,即一個事件源,多個響應者。在具體技術上,.NET Framework 的事件處理機制是基于多路委托實現的。事件與多路委托其實大同小異,只不過多路委托允許在事件源對象之外激發事件罷了。所有的.NET Framework 可視化窗體控件的預定義事件,都是某一對應的“事件名+Handler”委托類型的變量。與此事件相關的信息都封裝在“事件名+Args”類型的事件參數中,此事件參數有一個基類EventArgs,它是所有事件參數的基類。明了上述內部機理,對于我們在程序中定義自己的事件非常有好處,尤其是開發一個自定義的可視化控件時,如果需要增加新的事件類型,我們應盡量遵循.NET Framework 的定義事件的框架,給事件取一個名字,定義一個“事件名+Handler”的事件委托類型,再從EventArgs 派生出自定義事件的參數,取名為“事件名+Args”。 面向對象的軟件系統有許多都是事件驅動的,ASP.NET 就采用了“事件驅動”的編程方式。所謂“事件驅動”的開發方式,就是指整個系統包含許多的對象,這些對象可以引發多種事件,軟件工程師的主要開發工作就是針對特定的事件書寫代碼響應它們。.NET 事件處理機制建立在委托的基礎之上,而這兩者都是ASP.NET 技術的基礎之一。因此,必須牢固地掌握好委托和事件這兩種編程技術,才能為掌握ASP.NET 技術掃清障礙。 Java面向對象的學習心得 大三的時候學校組織我們去蘇州NIIT參加四個月的java實訓,我開始系統的學習期java,之前大學的時候學的比較寬泛,沒有專門的正對java的學習。 首先我是從學習Java編程開始接觸OOP(面向對象編程),剛開始使用Java編寫程序的時候感覺很別扭,因為我早以習慣用C來編寫程序,很欣賞C的簡潔性和高效性,喜歡C簡練而表達能力豐富的風格,特別忍受不了Java運行起來慢吞吞的速度,相對冗長的代碼,而且一個很簡單的事情,要寫好多類,一個類調用一個類,心里的抵觸情緒很強。 我對Java的面向對象的特性琢磨良久,自認為有所領悟,也開始有意識的運用OOP風格來寫程序,然而還是經常會覺得不知道應該怎樣提煉類,面對一個具體的問題的時候,會覺得腦子里千頭萬緒的,不知道怎么下手,一不小心,又會回到原來的思路上去。 舉個例子,要發廣告郵件,廣告郵件列表存在數據庫里面。倘若用C來寫的話,一般會這樣思考,先把郵件內容讀入,然后連接數據庫,循環取郵件地址,調用本機的qmail的sendmail命令發送。 然后考慮用Java來實現,既然是OOP,就不能什么代碼都塞到main過程里面,于是就設計了三個類: 一個類是負責讀取數據庫,取郵件地址,調用qmail的sendmail命令發送; 一個類是讀郵件內容,MIME編碼成HTML格式的,再加上郵件頭; 一個主類負責從命令讀參數,處理命令行參數,調用發email的類。 把一件工作按照功能劃分為3個模塊分別處理,每個類完成一件模塊任務。 仔細的分析一下,就會發現這樣的設計完全是從程序員實現程序功能的角度來設計的,或者說,設計類的時候,是自低向上的,從機器的角度到現實世界的角度來分析問題的。因此在設計的時候,就已經把程序編程實現的細節都考慮進去了,企圖從底層實現程序這樣的出發點來達到滿足現實世界的軟件需求的目標。 這樣的分析方法其實是不適用于Java這樣面向對象的編程語言,因為,如果改用C語言,封裝兩個C函數,都會比Java實現起來輕松的多,邏輯上也清楚的多。 我覺得面向對象的精髓在于考慮問題的思路是從現實世界的人類思維習慣出發的,只要領會了這一點,就領會了面向對象的思維方法。 舉一個非常簡單的例子:假使現在需要寫一個網頁計數器,客戶訪問一次頁面,網頁計數器加1,計數器是這樣來訪問的后臺有一個數據庫表,保存每個id(一個id對應一個被統計訪問次數的頁面)的計數器當前值,請求頁面一次,對應id的計數器的字段加1(這里我們忽略并發更新數據庫 表,出現的表鎖定的問題)。 如果按照一般從程序實現的角度來分析,我們會這樣考慮:首先是從HTTP GET請求取到id,然后按照id查數據庫表,獲得某id對應的訪問計數值,然后加1,更新數據庫,最后向頁面顯示訪問計數。 現在假設一個沒有程序設計經驗的人,他會怎樣來思考這個問題的呢?他會提出什么樣的需求呢?他很可能會這樣想: 我需要有一個計數器,這個計數器應該有這樣的功能,刷新一次頁面,訪問量就會加1,另外最好還有一個計數器清0的功能,當然計數器如果有一個可以設為任意值的功能的話,我就可以作弊了。 做為一個沒有程序設計經驗的人來說,他完全不會想到對數據庫應該如何操作,對于HTTP變量該如何傳遞,他考慮問題的角度就是我有什么需求,我的業務邏輯是什么,軟件應該有什么功能。 按照這樣的思路(請注意,他的思路其實就是我們平時在生活中習慣的思維方式),我們知道需要有一個計數器類 Counter,有一個必須的和兩個可選的方法: getCount()// 取計數器值方法 resetCounter()// 計數器清0方法 setCount()// 設計數器為相應的值方法 把Counter類完整的定義如下: public class Counter { public int getCount(int id){} public void resetCounter(int id){} public void setCount(int id, int currentCount){} } 解決問題的框架已經有了,來看一下如何使用Counter。在count.cgi里面調用Counter來計數,程序片斷如下: // 這里從HTTP環境里面取id值 ...Counter myCounter = new Counter();// 獲得計數器 int currentCount = myCounter.getCount(id);// 從計數器中取計數 // 這里向客戶瀏覽器輸出 ...程序的框架全都寫好了,剩下的就是實現Counter類方法里面具體的代碼了,此時才去考慮具體的程序語言實現的細節,比如,在getCount()方法里面訪問數據庫,更新計數 值。 從上面的例子中看到,面向對象的思維方法其實就是我們在現實生活中習慣的思維方式,是從人類考慮問題的角度出發,把人類解決問題的思維方式逐步翻譯成程序能夠理解的思維方式的過程,在這個翻譯的過程中,軟件也就逐步被設計好了。 在運用面向對象的思維方法進行軟件設計的過程中,最容易犯的錯誤就是開始分析的時候,就想到了程序代碼實現的細節,因此封裝的類完全是基于程序實現邏輯,而不是基于解決問題的業務邏輯。 學習JDBC編程的經典錯誤問法是:“我怎樣封裝對數據庫的select操作?” 面向對象的設計是基于解決業務問題的設計,而不是基于具體編程技術的設計。我不會去封裝select語句的,我只封裝解決問題的業務邏輯,對數據庫的讀取是在業務邏輯的編碼實現階段才去考慮的問題。 回過頭看上面那個發廣告郵件的例子,應該如何應用面向對象的思維方法呢? 對于一個郵件來說,有郵件頭,郵件體,和郵件地址這三個屬性,發送郵件,需要一個發送的方法,另外還需要一個能把所有郵件地址列出來的方法。所以應該如下設計: 類JunkMail 屬性: head body address 方法: sendMail()// 發送郵件 listAllMail()// 列郵件地址 用Java來表示: public class JunkMail { private String head; private String body; private String address; public JunkMain(){ // 默認的類構造器 // 從外部配置文件讀郵件頭和郵件體 this.head=...; this.body=...; } public static boolean sendMail(String address){ // 調用qmail,發送email } public static Collection listAllMail(){ // 訪問數據庫,返回一個郵件地址集合} } 當把JunkMail設計好了以后,再調用JunkMail類完成郵件的發送,將是非常輕松的事情。 如果說傳統的面向過程的編程是符合機器運行指令的流程的話,那么面向對象的思維方法就是符合現實生活中人類解決問題的思維過程。 在面向對象的軟件分析和設計的時候,要提醒自己,不要一上來就去想程序代碼的實現,應該拋開具體編程語言的束縛,集中精力分析我們要實現的軟件的業務邏輯,分析軟件的業務流程,思考應該如何去描述和實現軟件的業務。畢竟軟件只是一個載體,業務才是我們真正要實現的目標。 但是在設計過程中,心里卻往往在擔心,如果我完全不去考慮程序代碼的實現的話,那么我怎么知道我的設計一定合理呢?我怎么知道我設計的類、接口一定可以實現呢?所以經常可以看到的現象就是: 在設計過程中,雖然知道不能過早考慮代碼實現,但是每設計一個類,一個接口,心里都要不知不覺的用自己熟悉的編程語言大概的評估一下,看看能否編出來,因此,一不小心,就會又回到按照程序功能實現的思路進行設計的老路上去了。 舉個例子來說明,在做Web程序設計的時候,經常要遇到分頁顯示數據的情況。比如說需要把系統中所有的用戶都列出來這樣的功能。假設使用User類來表示用戶,增加用戶addUser(),刪除用戶deleteUser(),查詢所有用戶listUsers()方法。而數據庫中有一個user表,一條記錄是一個用戶的信息。下面考慮一下User類的方法的實現: addUser()和deleteUser()方法都好實現,就是對數據庫增加記錄和刪除記錄。對于listUsers()方法,其實就是對user表的select,取出一個記錄集。但是該怎么從listUsers()方法中得到所有用戶的列表呢? 一個方法調用的返回值只有一個,沒有多個,所以很多情況下采用的辦法就是返回值定義為集合類型,比如Vector。這樣就可以在listUsers()方法的具體代碼實現的時候,從數據庫依次取出一個個記錄,插入到Vector里面來。在主程序里面,調用listUsers()方法可以返回一個Vector,然后再對Vector遍歷操作,就可以得到用戶列表了。 public class User { public static void addUser(...){ // 數據庫insert一條記錄 } public static void deleteUser(...){ // 數據庫delete一條記錄 } public Vector listUsers(...){ // 數據庫select結果放到一個集合里面 } } 這樣的設計基本合理,但是仍然有點小問題。因為在設計的時候,就考慮到了用Java的集合類Vector來實現對不定長數據集的存放,因而違反了面向對象設計的一個原則:在設計的時候不應過早的考慮具體程序語言的實現。所以必須用抽象的方法,和具體實現無關的方法來表達業務邏輯。 我們知道,通常對具有集合特征的數據結構進行遍歷通常可以使用next和hasNext方法,next實現取下一個用戶,hasNext判斷是否還有元素。因此我們定義一個接口Iterator,這個接口中定義兩個方法next和hasNext: public interface Iterator { public boolean hasNext(){} public Object next(){} } 而User類的listUses方法返回值改為Iterator接口的實現類: public class User { ...public Iterator listUsers(){ } ...} 這樣就把User類的設計和具體的實現方法分離開了,因為此時任何實現了next()和hasNext()方法的類都可以做為listUsers的返回值,都可以被用來表達“用戶列表”,而不僅僅可以使用Vector而已。比如,我可以用ArrayList來表達用戶列表,因為ArrayList也實現了Iterator,當然我也可以自己專門寫一個類來存放用戶列表,只要實現next()和hasNext()方法就行了。 這樣在具體的編寫代碼的時候,程序員具有了最大的靈活性,可以根據具體的情況,采用不同的編程方法來存放用戶列表。特別是降低了程序的耦合度,提高了程序的可移植性。對于上面那個JunkMail的listAllMail()方法也同樣應該改為接口類型。 然后,在主程序里面就這樣來使用User類的listUsers方法: User myUser = new User(); Iterator iterator = myUser.listUsers(); while(iterator.hasNext()){ iterator.next(); } 這樣就可以完全不用考慮程序代碼實現了,從高層次上把功能抽象出來,定義成為接口,同時又可以把系統設計的很合理,完全根據業務的需求來進行設計。 結語 通過上面的幾個例子的設計說明,使用面向對象的思維方法,其實是一個把業務邏輯從具體的編程技術當中抽象出來的過程,而這個抽象的過程是自上而下的,非常符合人類的思維習慣,也就是先不考慮問題解決的細節,把問題的最主要的方面抽象成為一個簡單的框架,集中精力思考如何解決主要矛盾,然后在解決問題的過程中,再把問題的細節分割成一個一個小問題,再專門去解決細節問題。 因而一旦牢牢的抓住了這一點,你就會發現在軟件設計和開發過程中,你自己總是會不知不覺的運用面向對象的思維方法來設計和編寫程序,并且程序的設計和開發也變得不再那么枯燥,而一個合理運用面向對象技術進行設計和架構的軟件,更是具備了思維的藝術美感。 最后,愿面向對象的思維方法也能給您的程序設計之路帶來創作的樂趣。第二篇:達內學習心得:精心總結的面向對象
第三篇:學習心得《面向對象》
第四篇:C#面向對象學習心得
第五篇:java面向對象的學習心得