前言
僅供學(xué)習(xí)和參考,文章內(nèi)容來自相關(guān)書籍和搜索引擎以及一些個(gè)人的思考和心得。如有紕漏剔桨,歡迎指正讥珍。
七大原則
① 開閉原則
② 依賴倒置原則
③ 單一職責(zé)原則
④ 接口隔離原則
⑤ 迪米特法則
⑥ 里氏替換原則
⑦ 合成復(fù)用原則
開閉原則
開閉原則(Open-Closed Principle),對于一個(gè)軟件實(shí)體毁菱,應(yīng)該對拓展開放米死,對修改關(guān)閉锌历。對修改關(guān)閉即保證了軟件的一個(gè)完整性,保留了當(dāng)前版本的基本功能峦筒,在做版本更迭的時(shí)候也方便向下兼容究西。試想如果我們每次更新都直接對代碼進(jìn)行修改,那么需要新功能的用戶會進(jìn)行軟件更新勘天,但是那些不需要新功能的呢怔揩?他們也必須更新代碼,不然就會出問題脯丝。所以商膊,在保證了對修改關(guān)閉的同時(shí),也必須對拓展開放宠进,拓展性的是每個(gè)系統(tǒng)必要條件晕拆,因?yàn)槟阌肋h(yuǎn)不知道客戶會有什么需求 。
作用
1材蹬、通過擴(kuò)展已有軟件系統(tǒng),可以提供新的行為,以滿足對軟件新的需求,提高了軟件系統(tǒng)的適應(yīng)性和靈活性
2实幕、已有的軟件模塊,特別是重要的抽象層模塊不能再修改,提高了軟件系統(tǒng)的一定的穩(wěn)定性和延續(xù)性
3、這樣的設(shè)計(jì)同時(shí)也滿足了可復(fù)用性和可維護(hù)性
在實(shí)際開發(fā)中堤器,如何去實(shí)現(xiàn)開閉原則呢?
實(shí)現(xiàn)開閉原則的關(guān)鍵是抽象
1昆庇、橫向拓展
世界上的高級物種只有人類
public interface Human {
String getName();
String getSexLike();
String getSex();
}
此時(shí),然后女媧首先捏了一個(gè)男娃兒
public class man implements Human{
private String name;
private String sexLike;
private String sex;
@Override
public String getName() {
return name;
}
@Override
public String getSexLike() {
return sexLike;
}
@Override
public String getSex() {
return sex;
}
}
然后女媧又捏了一個(gè)女娃兒闸溃,此時(shí)就可以進(jìn)行橫向拓展整吆,而不必修改man中的getSex()的方法讓他return "女"。因?yàn)閙an中的getSex()方法可能被其他方法調(diào)用辉川。
public class woman implements Human{
private String name;
private String sexLike;
private String sex;
@Override
public String getName() {
return name;
}
@Override
public String getSexLike() {
return sexLike;
}
@Override
public String getSex() {
return sex;
}
}
2表蝙、縱向拓展
此時(shí),女媧又捏了一個(gè)男娃兒乓旗,但是他喜歡男人府蛇。此時(shí)可以進(jìn)行縱向拓展
public class gay extends man{
@Override
public String getSexLike() {
return "男";
}
}
依賴倒置原則
依賴倒置原則(Dependency Inversion Principle)是指高層模塊不應(yīng)該依賴底層模塊,兩者都應(yīng)該依賴抽象屿愚,抽象不應(yīng)該依賴細(xì)節(jié)汇跨,細(xì)節(jié)應(yīng)該依賴抽象。其中:
高層模塊:調(diào)用者
底層模塊:被調(diào)用者
抽象:即是抽象類或者接口渺鹦,兩者是不能夠?qū)嵗?br>
細(xì)節(jié):即是具體的實(shí)現(xiàn)扰法,實(shí)現(xiàn)接口或者繼承抽象類的類
其實(shí)該原則更像是對開閉原則的一種具體實(shí)現(xiàn),如果高層模塊直接依賴具體實(shí)現(xiàn)毅厚,那么每一次修改的時(shí)候就必須修改具體實(shí)現(xiàn)類(耦合度太高)塞颁,這就違背了開閉原則。其實(shí)依賴倒置原則在我看來更像現(xiàn)在得房屋租賃。大多數(shù)房東不能夠直接去找到租房人員(高層模塊不應(yīng)該依賴底層模塊)祠锣,大多數(shù)租房人員也不容易找到房東酷窥,兩者都需要通過中介進(jìn)行交易(兩者都應(yīng)該依賴抽象),中介租房不需要管房子是什么樣子的伴网,只需要將它租出去(抽象不應(yīng)該依賴細(xì)節(jié))蓬推,但租房人員有需求,必須找到中介(細(xì)節(jié)應(yīng)該依賴抽象)澡腾。
但是我有一點(diǎn)不明白沸伏,這個(gè)原則為什么叫依賴倒置原則呢?"倒置"动分,不應(yīng)該是倒過來么毅糟?這更像是"中間商原則"。
作用
采用依賴倒置原則可以降低模塊之間的耦合性,提高系統(tǒng)的穩(wěn)定性,減少并行開發(fā)的風(fēng)險(xiǎn),提高代碼的可讀性和可維護(hù)性
在實(shí)際開發(fā)中澜公,如何去實(shí)現(xiàn)依賴倒置原則呢?
在我上述租房例子中姆另,房東就是高層模塊,租戶就是底層模塊坟乾,中介就是抽象迹辐,房子的類型就是細(xì)節(jié)
高層模塊在開發(fā)中就是main()方法,因?yàn)樗浅绦虻娜肟谏趼拢?fù)責(zé)調(diào)用其他明吩。
1、不使用依賴倒置原則
底層模塊——租戶
public class Renter {
public void rentOneRoom(){
System.out.println("租戶租到1室");
}
public void rentOneBadRoom(){
System.out.println("租戶租到1室1廳");
}
}
高層模塊——房東
public class Landlord {
public static void main(String[] args) {
Renter renter = new Renter();
renter.rentOneRoom();
renter.rentOneBadRoom();
}
}
租戶租到1室
租戶租到1室1廳
如果此時(shí)租戶還想租兩室一廳呢殷费?我們又需要去Renter里添加租兩室一廳的方法贺喝,在landlord里增加兩室一廳的調(diào)用方法。這樣頻繁的添加代碼宗兼,會有一些風(fēng)險(xiǎn),影響系統(tǒng)的穩(wěn)定性氮采。
2殷绍、使用依賴倒置原則
定義抽象——中介
public interface Agent {
void rent();
}
定義細(xì)節(jié)——一室一廳、一室鹊漠、兩室一廳(創(chuàng)建3個(gè)java文件主到,此處圖方便,代碼貼在一起)
public class OneBadRoom implements Agent{
@Override
public void rent() {
System.out.println("租戶租到1室1廳");
}
}
public class OneRoom implements Agent{
@Override
public void rent() {
System.out.println("租戶租到1室");
}
}
public class TwoBadRoom implements Agent{
@Override
public void rent() {
System.out.println("租戶租到2室1廳");
}
}
定義底層模塊——租戶
public class Renter {
public void rent(Agent agent){
agent.rent();
}
}
定義高層模塊——房東
public class Landlord {
public static void main(String[] args) {
Renter renter = new Renter();
renter.rent(new OneRoom());
renter.rent(new OneBadRoom());
renter.rent(new TwoBadRoom());
}
}
租戶租到1室
租戶租到1室1廳
租戶租到2室1廳
這樣以后租戶想租新的房子只需要增加細(xì)節(jié)(房子的類型)即可躯概。而不需要修改底層代碼登钥。這種方式就叫做依賴注入。
其他依賴注入方式還有
構(gòu)造器方式
修改租戶Renter
public class Renter {
private Agent agent;
public Renter(Agent agent){
this.agent = agent;
}
public void rent(){
agent.rent();
}
}
修改房東Loadlord
public class Landlord {
public static void main(String[] args) {
Renter renter = new Renter(new OneRoom());
renter.rent();
}
}
租戶租到1室
setter方式
修改租戶Renter
public class Renter {
private Agent agent;
public void setAgent(Agent agent){
this.agent = agent;
}
public void rent(){
agent.rent();
}
}
修改房東Loadlord
public class Landlord {
public static void main(String[] args) {
Renter renter = new Renter();
renter.setAgent(new OneRoom());
renter.rent();
}
}
租戶租到1室
單一職責(zé)原則
單一職責(zé)原則(Simple Responsibility Principle)娶靡,顧名思義牧牢,就是專人干專事。反過來想,如果系統(tǒng)出了問題塔鳍,有多種原因要去改一個(gè)類伯铣,那就說明這個(gè)類有多種職責(zé)。而且單一職責(zé)并不是單一功能轮纫。
作用
將功能分類腔寡,模塊劃分明確,修改一個(gè)模塊不會造成其他模塊的修改掌唾,降低模塊之間的耦合度
比如查找一個(gè)商品信息放前,前臺查找商品信息用于展示,后臺查詢商品信息用于管理糯彬。但是如下代碼既承擔(dān)了前臺查詢的職責(zé)凭语,又承擔(dān)了后臺查詢的職責(zé)。那么前臺需要展示的信息需要改變時(shí)情连,會對后臺也產(chǎn)生影響
1叽粹、不遵循單一職責(zé)原則
@Repository
public class Repository {
@Select("<script>" +
"select feild1,field2,field3 from table")
List<XXX> getSomeThing();
}
2、遵循單一職責(zé)原則
@Repository
public class Repository {
@Select("<script>" +
"select feild1,field2,field3 from table")
List<XXX> getSomeThingForProtal();
@Select("<script>" +
"select feild1,field4,field5 from table")
List<XXX> getSomeThingForBackend();
}
創(chuàng)建兩個(gè)方法分別服務(wù)前臺后臺却舀,這就滿足了粗粒度的單一職責(zé)原則虫几。
我們常說的高內(nèi)聚低耦合原則其實(shí)就是單一職責(zé)的具體體現(xiàn)。單一職責(zé)原則是最簡單也非常難實(shí)現(xiàn)的原則
接口隔離原則
接口隔離原則(interface Segregation Principle)是指用多個(gè)專門的接口挽拔,而不使用單一的總接口辆脸,客戶端不應(yīng)該只依賴它不需要的接口。這個(gè)原則是在接口設(shè)計(jì)時(shí)的規(guī)范:
1螃诅、一個(gè)類對一類的依賴應(yīng)該建立在最小的接口之上啡氢。
2、建立單一接口术裸,不要建立龐大臃腫的接口倘是。
3、盡量細(xì)化接口袭艺,接口中的方法盡量少(不是越少越好搀崭,一定要適度)。
作用
防止龐大猾编,臃腫的接口瘤睹,避免接口污染,提高程序設(shè)計(jì)要求的細(xì)致劃分性答倡。降低大面積維護(hù)成本轰传,一旦出現(xiàn)接口污染,會造成實(shí)現(xiàn)類中存在大量的不相關(guān)不需要去重寫的方法
接口隔離原則符合我們常說的高內(nèi)聚低耦合的設(shè)計(jì)思想瘪撇,從而使得類具有很好的可讀性获茬、可擴(kuò)展性和可維護(hù)性港庄。我們在設(shè)計(jì)接口的時(shí)候,要多花時(shí)間去思考锦茁,要考慮業(yè)務(wù)模型攘轩,包括以后有可能發(fā)生變更的地方還要做一些預(yù)判。所以码俩,對于抽象度帮,對業(yè)務(wù)模型的理解是非常重要的。
1稿存、不遵循接口隔離原則
定義一個(gè)Animal類
public interface Animal {
void eat();
void fly();
void swim();
}
鳥類實(shí)現(xiàn)類
public class Bird implements Animal{
@Override
public void eat() {}
@Override
public void fly() {}
@Override
public void swim() {}
}
狗類實(shí)現(xiàn)類
public class Dog implements Animal{
@Override
public void eat() {}
@Override
public void fly() {}
@Override
public void swim() {}
}
可以看出笨篷,Bird 的 swim()方法可能只能空著,Dog 的 fly()方法顯然不可能的瓣履。
2率翅、遵循接口隔離原則
這時(shí)候,我們針對不同動(dòng)物行為來設(shè)計(jì)不同的接口袖迎,分別設(shè)計(jì) IEatAnimal冕臭,IFlyAnimal 和ISwimAnimal 接口
public interface EatAnimal {
void eat();
}
public interface FlyAnimal {
void fly();
}
public interface SwimAnimal {
void swim();
}
Dog 只實(shí)現(xiàn) IEatAnimal 和 ISwimAnimal 接口
public class Dog implements EatAnimal, SwimAnimal{
@Override
public void eat() {}
@Override
public void swim() {}
}
這樣拆分下來,就清晰很多燕锥。接口隔離原則也是高內(nèi)聚低耦合的思想辜贵,那么它跟接口單一職責(zé)有什么區(qū)別呢?
單一職責(zé)和接口隔離辨析
1归形、單一職責(zé)原則側(cè)重職責(zé),接口隔離側(cè)重對接口的依賴的隔離
2托慨、單一職責(zé)原則側(cè)重約束類,其次是接口,針對程序中實(shí)現(xiàn)的細(xì)節(jié)
3、接口隔離原則側(cè)重約束接口,主要針對抽象需求,針對程序的整體框架的構(gòu)建
轉(zhuǎn)載請注明出處
http://www.reibang.com/p/4615cfb77e97