面向對象設計的 10 條戒律
這也不是Jon Skeet / Martin Fowler / Jeff Atwood / Joel Spolsky(可以用你最喜歡的技術專家的替換這些名字)說的。
我們正在審查一些代碼,并開始討論為什么我們走捷徑,不遵循常識原則。雖然每個人在對待關于類應該如何基于功能上下文來構建的問題上都有自己的智慧,但仍然有一些基本原則值得我們在設計類的時候牢牢記住。
1.遵循單一職責原則
每個類都應該有一個并且只有一個引起它變化的原因。這不僅適用于類,方法也是如此。不知道你有沒有見到過那些長篇大論的冗余的類和方法,當將它們寫到紙上的時候,簡直就是懶婆娘的裹腳布——又臭又長?好吧,我們要提出的觀點是不要這樣做。
該原則的要點就是每個類或方法都有一個存在的理由。如果類被命名為Loan,那么它就不應該處理銀行帳戶的相關細節。如果方法被命名為GetLoanDetails,那么它應該負責獲取貸款的詳細信息!
2.遵循開放封閉原則
這一條使你能夠思考你的系統將如何適應未來的變化。它指出,系統應該允許添加新的功能,但對現有代碼的更改要做到最少。因此,設計對于擴展應該是開放的,但對于修改應該是封閉的。在我們的例子中,開發人員做了這樣的事情:
public class PersonalLoan
{
public void Terminate()
{
//Execute Termination related rules here and terminate a personal loan
}
}
public class AutoLoan
{
public void Terminate()
{
//Execute Termination related rules here and terminate a personal loan
}
}
public class LoanProcessor
{
public void ProcessEarlyTermination(object loan)
{
if ( loan is PersonalLoan )
{
//Personal Loan processing
}
else if (loan is AutoLoan)
{
//Auto Loan Processing
}
}
}
LoanProcessor的問題是,當有一種新類型的Loan,例如HomeLoan出現的時候,它將不得不改變。結構最好是這樣:
public abstract class Loan
{
public abstract void Terminate();
}
public class PersonalLoan: Loan
{
public override void Terminate()
{
//Execute Termination related rules here and terminate a personal loan
}
}
public class AutoLoan: Loan
{
public override void Terminate()
{
//Execute Termination related rules here and terminate a personal loan
}
}
public class LoanProcessor
{
public void ProcessEarlyTermination(Loan loan)
{
loan.Terminate();
}
}
這樣的話,如果添加了新類型的Loan,那么LoanProcessor也不會受影響。
3.嘗試使用組合優于繼承
如果不能正確地遵循這一條原則,那么可能會導致脆弱的類層次。這個原則真的很簡單,只需要問一個問題——如果我要看子類,那么我能不能說“Child是Parent的一種類型?”或者,它更像“Child某種程度上是Parent的一種類型?“
始終對第一個問題使用繼承,因為它將允許使用Child無論Parent在哪里。這也將允許你能夠實現另一個稱為Liskov替代原則的設計原則。并且在你想部分使用一個類的功能的時候使用組合。
4.封裝數據和行為
大多數開發人員只做數據封裝,忘記封裝基于上下文而變化的代碼。不但隱藏類的私有數據很重要,而且創建被良好封裝的作用于私有數據的方法也很重要。
5.類遵循松散耦合原則
這與封裝正確的行為是相輔相成的。如果行為被很好地封裝在類中,那么就只能創建松散耦合的類。我們可以通過依賴于抽象而不是實現來做到松散耦合。
6.使類高度內聚
我們不應該在不同的類之間散開數據和行為。應該努力使類不泄露/打破實現到其他類的細節。這意味著不允許類有代碼,因為這樣超出了它存在的目的。當然,有一些設計范例,如CQRS,會希望你在不同的類中隔離某些類型的行為,但它們只用于分布式系統。
7.編碼接口而不是實現
這促進了松散耦合原則,并使得我們能夠改變底層實現或引入新的實現,而不影響使用它們的類。
8.保持DRY(Don’t Repeat Yourself)
也是一個聲明不要在兩個不同的地方重復相同代碼的設計原則。也就是說,特定功能或算法應當,僅,在一個地方實現。如果重復實現的話,則會導致維護問題。與此相反的是WET原則——Write Everything Twice。
9.最少知識原則,也叫做迪米特法則。
這個原則聲明對象不應該知道它協作對象的內部細節。它被著名地稱為——與朋友交流,不要和朋友的朋友交流。類應該只能調用它正在協作的類的公共數據成員。不應該被允許訪問由那些數據成員組成的類的行為或數據。如果不能正確遵守,則會導致緊密耦合,從而創建出更難改變的系統。
10.遵循好萊塢原則:Don’t Call Us, We’ll Call You
這能夠打破條件流邏輯的模型,并允許基于事件執行代碼。這要么通過事件回調,要么通過注入接口的實現來完成。依賴注入,控制反轉或觀察者設計模式都是這個原則的好例子。這個原則促進了類之間的松散耦合,并使得實現非常可維護。
來自:http://www.jointforce.com/jfperiodical/article/3457