概述
簡(jiǎn)單介紹一下七大設(shè)計(jì)原則:
開(kāi)閉原則:是所有面向?qū)ο笤O(shè)計(jì)的核心,對(duì)擴(kuò)展開(kāi)放整慎,對(duì)修改關(guān)閉
依賴倒置原則:針對(duì)接口編程,依賴于抽象而不依賴于具體
單一職責(zé)原則:一個(gè)接口只負(fù)責(zé)一件事情围苫,只能有一個(gè)原因?qū)е骂愖兓?br> 接口隔離原則:使用多個(gè)專門的接口裤园,而不是使用一個(gè)總接口
迪米特法則(最少知道原則):只和朋友交流(成員變量、方法輸入輸出參數(shù))剂府,不和陌生人說(shuō)話拧揽,控制好訪問(wèn)修飾符
里氏替換原則:子類可以擴(kuò)展父類的功能,但不能改變父類原有的功能
合成復(fù)用原則:盡量使用對(duì)象組合(has-a)/聚合(contanis-a),而不是繼承關(guān)系達(dá)到軟件復(fù)用的目的
單一職責(zé)原則
定義
單一職責(zé)(Simple Responsibility Pinciple淤袜,SRP)是指不要存在多于一個(gè)導(dǎo)致類變更 的原因痒谴。
假設(shè)我們有一個(gè) Class 負(fù)責(zé)兩個(gè)職責(zé),一旦發(fā)生需求變更铡羡,修改其中一個(gè)職責(zé)的邏輯代碼积蔚,有可能會(huì)導(dǎo)致另一個(gè)職責(zé)的功能發(fā)生故障。這樣一來(lái)烦周,這個(gè) Class 存在兩個(gè)導(dǎo) 致類變更的原因尽爆。如何解決這個(gè)問(wèn)題呢?我們就要給兩個(gè)職責(zé)分別用兩個(gè) Class 來(lái)實(shí)現(xiàn), 進(jìn)行解耦读慎。后期需求變更維護(hù)互不影響漱贱。這樣的設(shè)計(jì),可以降低類的復(fù)雜度贪壳,提高類的 可讀性饱亿,提高系統(tǒng)的可維護(hù)性,降低變更引起的風(fēng)險(xiǎn)闰靴”肓總體來(lái)說(shuō)就是一個(gè) Class/Interface/Method 只負(fù)責(zé)一項(xiàng)職責(zé)。
示例
接下來(lái)我們參考《設(shè)計(jì)模式之禪》一書(shū)中所提到關(guān)于用戶信息管理的示例來(lái)舉例:
新建用戶信息IUserInfo
類:
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:07
*/
public interface IUserInfo {
void setUserID(String userID);
String getUserID();
void setPassword(String password);
String getPassword();
void setUserName(String userName);
String getUserName();
boolean changePassword(String oldPassword);
boolean deleteUser();
void mapUser();
boolean addOrg(int orgID);
boolean addRole(int roleID);
}
用戶信息維護(hù)類圖:
如果像這樣子來(lái)設(shè)計(jì)蚂且,即使是一個(gè)初級(jí)程序員也可以看出這個(gè)解耦設(shè)計(jì)得有問(wèn)題配猫,用戶的屬性和用戶的行為沒(méi)有分離開(kāi)。應(yīng)該把用戶的信息抽離成為一個(gè)BO
杏死,把行為抽離成為一個(gè)Biz
(業(yè)務(wù)邏輯)泵肄。然后我們修改這個(gè)接口。
創(chuàng)建 IUserBo
類:
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:18
*/
public interface IUserBO {
void setUserID(String userID);
String getUserID();
void setPassword(String password);
String getPassword();
void setUserName(String userName);
String getUserName();
}
創(chuàng)建 IUserBiz
類:
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:18
*/
public interface IUserBiz {
boolean changePassword(String oldPassword);
boolean deleteUser();
void mapUser();
boolean addOrg(int orgID);
boolean addRole(int roleID);
}
職責(zé)劃分后的類圖:
我們將IUserInfo
拆分為了IUserBo
和IUserBiz
淑翼。我們就實(shí)現(xiàn)了兩個(gè)類的單一職責(zé),也就是讓引起他們變化原因只有一種,并且讓相關(guān)性強(qiáng)的內(nèi)容聚合在一個(gè)類內(nèi)部腐巢。
但是,我們?cè)趯?shí)際開(kāi)發(fā)中會(huì)項(xiàng)目依賴玄括,組合冯丙,聚合這些關(guān)系,還有還有項(xiàng)目的規(guī)模遭京,周期胃惜,技術(shù)人員的水平,對(duì)進(jìn)度的把控哪雕,很多類都不符合單一職責(zé)船殉。但是,我們?cè)诰帉?xiě)代碼的過(guò)程斯嚎,盡可能地讓接口和方法保持 單一職責(zé)利虫,對(duì)我們項(xiàng)目后期的維護(hù)是有很大幫助的挨厚。
接口隔離原則
定義
接口隔離原則(Interface Segregation Principle, ISP)是指用多個(gè)專門的接口,而不使 用單一的總接口列吼,客戶端不應(yīng)該依賴它不需要的接口幽崩。這個(gè)原則指導(dǎo)我們?cè)谠O(shè)計(jì)接口時(shí) 應(yīng)當(dāng)注意一下幾點(diǎn):
- 一個(gè)類對(duì)一類的依賴應(yīng)該建立在最小的接口之上。
- 建立單一接口寞钥,不要建立龐大臃腫的接口慌申。
- 盡量細(xì)化接口,接口中的方法盡量少(不是越少越好理郑,一定要適度)蹄溉。
接口隔離原則符合我們常說(shuō)的高內(nèi)聚低耦合的設(shè)計(jì)思想,從而使得類具有很好的可讀性您炉、 可擴(kuò)展性和可維護(hù)性柒爵。我們?cè)谠O(shè)計(jì)接口的時(shí)候,要多花時(shí)間去思考赚爵,要考慮業(yè)務(wù)模型棉胀,包括以后有可能發(fā)生變更的地方還要做一些預(yù)判。所以冀膝,對(duì)于抽象唁奢,對(duì)業(yè)務(wù)模型的理解 是非常重要的。
示例
下面我們來(lái)看一段代碼窝剖,寫(xiě)一個(gè)動(dòng)物行為的抽象:
IAnimal
接口:
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:56
*/
public interface IAnimal {
void eat();
void fly();
void swim();
}
Bird
類實(shí)現(xiàn):
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:57
*/
public class Bird implements IAnimal {
public void eat() {
}
public void fly() {
}
public void swim() {
}
}
Dog
類實(shí)現(xiàn):
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:57
*/
public class Dog implements IAnimal {
public void eat() {
}
public void fly() {
}
public void swim() {
}
}
可以看出麻掸,Bird
的 swim()
方法可能只能空著,Dog
的 fly()
方法顯然不可能的赐纱。這時(shí)候脊奋,我們針對(duì)不同動(dòng)物行為來(lái)設(shè)計(jì)不同的接口,分別設(shè)計(jì) IEatAnimal
疙描,IFlyAnimal
和 ISwimAnimal
接口诚隙,來(lái)看代碼:
IEatAnimal
接口:
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:59
*/
public interface IEatAnimal {
void eat();
}
IFlyAnimal
接口:
/**
* @author eamon.zhang
* @date 2019-09-25 下午5:01
*/
public interface IFlyAnimal {
void fly();
}
ISwimAnimal
接口:
/**
* @author eamon.zhang
* @date 2019-09-25 下午5:02
*/
public interface ISwimAnimal {
void swim();
}
Dog
只實(shí)現(xiàn) IEatAnimal
和 ISwimAnimal
接口:
/**
* @author eamon.zhang
* @date 2019-09-25 下午4:57
*/
public class Dog implements IEatAnimal,ISwimAnimal {
public void eat() {
}
public void swim() {
}
}
來(lái)看下兩種類圖的對(duì)比,還是非常清晰明了的:
聲明
內(nèi)容為原創(chuàng)起胰,轉(zhuǎn)發(fā)請(qǐng)注明出處久又!
部分內(nèi)容參考網(wǎng)絡(luò),侵刪待错!