溫故知新,最近更多的是研究和開發(fā)各種類庫,對設(shè)計的是有些感觸.以前在大學(xué)的時候,雖然知道,但是總歸是欠缺經(jīng)驗的,現(xiàn)在,我嘗試用最通俗易懂的方式說出來.
所謂的設(shè)計不正是采用恰當(dāng)?shù)姆绞浇M織雷類關(guān)系么?因此談設(shè)計我認(rèn)為首先要從類之間的關(guān)系開始說起.
在java開發(fā)中,有很多時候我們是在不斷的處理類與類之間關(guān)系,其中這六種關(guān)系是:依賴哼御、關(guān)聯(lián)、聚合恋昼、組合、繼承液肌、實現(xiàn),他們的耦合度依次增強,其在UML的表示如下:
下面我們分別對這幾種關(guān)系進行說明.
依賴
在實際生活中我們做任何一件事情幾乎都需要借助其他物體的幫助,換句話說矩屁,我們依賴于其他的物體生活爵赵。比如:小明要開車,小明要吃飯空幻,小明要生活等等,不難想象出依賴關(guān)系是現(xiàn)實世界中最普通的關(guān)系秕铛。對于以面向?qū)ο鬄樗枷氲恼Z言世界來說,依賴也是最普遍和常見的關(guān)系但两。
在代碼層次上,依賴關(guān)系多表現(xiàn)為函數(shù)的參數(shù).
public class Person{
public void drive(Car car){
//
}
}
UML表示:
關(guān)聯(lián)
如果說依賴關(guān)系講求的臨時性谨湘,偶然性的話,那么關(guān)聯(lián)關(guān)系則是一種持久性的關(guān)系紧阔。為什么這么說呢?
小明吃飯借助筷子擅耽,這種關(guān)系只存在小明吃飯的情況下活孩,一旦小明不吃飯了乖仇,那么這種依賴關(guān)系也就終止了。
與依賴關(guān)系不同乃沙,關(guān)聯(lián)對象的雙方地位同級,存在長期崔涂,固定的對應(yīng)關(guān)系,即關(guān)聯(lián)是一種強依賴。關(guān)聯(lián)關(guān)系共分為兩種:單向關(guān)聯(lián)和雙向關(guān)聯(lián)缭保。所謂單向關(guān)聯(lián)通俗點講就是“你中有我,但我中未必有你”艺骂,比如小明擁有一輛車(注意和小明開車進行區(qū)分),但車這個對象可不擁有你啊钳恕。和單向關(guān)聯(lián)相對應(yīng)的是雙向關(guān)聯(lián),也即是"你中有我,我中有你",比如夫妻就是一種雙向關(guān)聯(lián).
在代碼層次上,關(guān)聯(lián)關(guān)系表現(xiàn)為對象作為另一個類的成員變量.
單向關(guān)聯(lián)
public class Person{
private Car car;
public void setCar(Car car){
this.car=car;
}
}
UML表示:
雙向關(guān)聯(lián)
public class Husband{
private Wife wife=new Wife();
public void say(){
System.out.println("my wife name:"+wife.getName());
}
}
public class Wife{
private Husband husband=new Husband();
public void say(){
System.out.println("my husband name:"+husband.getName());
}
}
UML表示:
聚合
聚合關(guān)系是一種強關(guān)聯(lián)關(guān)系,兩者之間最主呀的區(qū)別是在語意上:聚合之間的關(guān)系更像是"整體-部分",有點組裝的含義,而關(guān)聯(lián)關(guān)系的對象間是相互獨立的,不存在組裝關(guān)系.
在現(xiàn)實世界中,分子是由原子組成的,汽車是由各種零部件組成的等,這都是聚合關(guān)系的最好說明.這里要注意,組成A類型分子的原子也可以組成B類型的分子,這說明什么呢?也就是部分可以單獨存在,換句話說就是整體和部分兩者的生命周期不是同步的.比如:水分子是由氧原子和氫原子組成的,你不能說沒有水分子就沒有氧原子和氫原子吧.
在代碼層次上,聚合和關(guān)聯(lián)兩者的形式一致,都表現(xiàn)為成員變量.
public class Car{
private Tyre tyre;
private Engine engine;
public void setTyre(Tyre tyre){
this.tyre=tyre;
}
public void setEngine(Engine engine){
this.engine=engine;
}
}
UML表示:
有些人寫成以下樣子:
public class Car{
private Tyre tyre=new Tyre();
private Engine engine=new Engine();
}
咋眼一看在代碼層次上符合啊,那這算不算是聚合關(guān)系呢?首先呢,我們肯定的說這是聚合關(guān)系.但僅僅是形勢上聚合的關(guān)系.為什么這么說呢?
我們從真實世界中抽象汽車這個概念,進而將其轉(zhuǎn)化為軟件世界中的Car,這也是java中提倡的面向?qū)ο缶幊痰?但是呢,在從真實世界到軟件世界的這個過程中需要保證物體靜態(tài)屬性和動態(tài)屬性沒變.什么意思呢,換言之就是,你將真實世界中的汽車轉(zhuǎn)成換成軟件世界中Car,反過來,也要保證從軟件世界中Car能夠轉(zhuǎn)換成真實世界中的汽車.如果不能保證轉(zhuǎn)換的一致性,那么就說明,抽象過程中出現(xiàn)了問題.
現(xiàn)在將上邊的代碼中的Car轉(zhuǎn)成現(xiàn)實世界中的汽車,我們發(fā)現(xiàn)轉(zhuǎn)換后的汽車竟然不能換車輪了?這可能嗎?很顯然,在對抽象汽車到Car這個類的過程中出現(xiàn)了問題.那么應(yīng)該怎么樣的呢?
除了一開始我們寫的那樣,還可以如下:
public class Car{
private Tyre tyre=new Tyre();
private Engine engine=new Engine();
public void setTyre(Tyre tyre){
this.tyre=tyre;
}
public void setEngine(Engine engine){
this.engine=engine;
}
}
組合
組合和聚合非常類似,都表示的"整體-部分",但是組合要求整體和部分的生命周期是同步的,部分不能脫離整體而存在.不難發(fā)現(xiàn),組合是一種強聚合關(guān)系.比如,人這個生命體由不同器官構(gòu)成,其中我們拿心臟來說一下,人要活著必須依靠心臟,心臟不能脫離人這個生命體,兩者一旦分開,都會死亡.
在代碼層次上,通常表現(xiàn)為類的成員變量,除此之外還要求這個成員變量在構(gòu)造函數(shù)中創(chuàng)建.
public class People{
private Heart heart;
public People(){
heart=new Heart();
}
}
UML表示:
到現(xiàn)在我們從微觀的角度了解依賴,關(guān)聯(lián),聚合和組合這四種關(guān)系,從宏觀上來說,這四種關(guān)系體現(xiàn)的都是對象與對象之間的依賴,因此在某些方面,我們也同依賴來涵蓋這四種關(guān)系.在很多文章中,并沒有說到這一點,這也造成,很多情況下,大家對這幾個概念探地的時候感到很疑惑.
從真實世界中來看,對象與對象之間的關(guān)系其實可以分為兩類,一是上邊宏觀所說的依賴,另一種則是我們下面要談的泛化
泛化
在開始解釋泛化之前,先來從extends說起:
extends的意思是延伸,擴展,繼承.從這個詞的角度來說,子類應(yīng)該分為兩層意思:
一種是增強原有類的功能,這體現(xiàn)的不是生物界的"父與子"關(guān)系.比如我現(xiàn)在擁有一個工具類Tools,現(xiàn)在我想要增強該工具類,按照開閉原則,我定義了
UpdateTools extends Tools
,此時你就不能說UpdateTools是Tools的"孩子",因為你發(fā)現(xiàn)這里的UpdateTools僅僅是增強原有Tools類的功能,作為功能擴展類來的.此時,我們稱其為擴展比較合適.
另一種則就是體現(xiàn)生物界的"父與子",即子類和父類在某些行為或者屬性的表現(xiàn)不一樣.這時候,用單詞inherit來表示更合適,也就是我們常說的繼承的意思.
到現(xiàn)在,相信你已經(jīng)明白了extends的含義.其實,實際中,我們使用繼承的目的就是為了擴展,因此,可不做深究.
之所以談到這一點,是因為去年帶過的一個實習(xí)生僅僅因為不理解extends中的兩層,而覺得通過UpdateTools擴展Tools是有問題的.
下面我們在來說泛化.
泛化表示一個類(父類或接口)與其一個或者多個變體之間的關(guān)系.簡單的來說泛化表示類與類之間的擴展,接口與接口的擴展,類與接口之間的實現(xiàn)關(guān)系.
在java中用extends來表示擴展,用implements表示實現(xiàn)關(guān)系.
擴展:
public class Tools{
public void print(){
//do
}
}
public class UpdateTools extens Tools{
public void printError(){
//do
|
}
繼承:
public class Father{
public void getName(){
//do
}
}
public class Son{
public void other(){
//do
}
}
UML表示:
實現(xiàn):
public interface UserService{
void execute();
}
public class UserServiceImpl implements UserService{
@override
void execute(){
//do
}
}
UML表示:
到現(xiàn)在厘肮,相信你對類關(guān)系有了清晰的理解了睦番。