軟件設計的七大原則html
六大設計原則(C#)【有代碼實例講解,有空看一下】數據庫
Figure, 重要的前五個原則編程
類的設計趨向於:Use Case Diagram --> (derived) --> Detail設計模式
就一個類而言,應該僅有一個引發它變化的緣由,若是你能想到多於一個的動機去改變一個類,那麼這個類就具備多於一個的職責.應該把多於的指責分離出去,分別再建立一些類來完成每個職責. 安全
/* Software entities should be open for extension, but closed for modification */架構
反面例子:Dependency: 做爲參數,做爲局部變量,調用靜態方法。框架
改進方式:增長抽象類或者接口,以及set方法。函數
再設計一個模塊的時候,應當使這個模塊能夠在不被修改的前提下被擴展.post
換言之,應當能夠在沒必要修改源代碼的狀況下改變這個模塊的行爲,在保持系統必定穩定性的基礎上,對系統進行擴展。性能
這是面向對象設計(OOD)的基石,也是最重要的原則。
[replace A with B 用B來代替A]
[substitute A for B 用A來代替B (或者A substitute for B)]
Derived Class 需嚴格成爲 Base Class 的子類型。
首先針對基類編程,在具體實現 或程序運行時再肯定具體子類。 <-- 實現開閉原則的重要基礎
應當儘可能從抽象類繼承,而不從具體類繼承,
通常而言,若是有兩個具體類A, B有繼承關係,那麼一個最簡單的修改方案是創建一個抽象類C,而後讓類A和B成爲抽象類C的子類.
即若是有一個由繼承關係造成的登記結構的話,那麼在等級結構的樹形圖上面全部的樹葉節點都應當是具體類;而全部的樹枝節點都應當是抽象類或者接口.
接口杜絕臃腫,以避免空方法實現。
傾向瘦接口。
除去set方法,也可採用讀取配置文件來選擇類的調用。<-- 實現開閉原則的重要手段
接口與抽象的區別就在於抽象類能夠提供某些方法的部分實現,而接口則不能夠,這也大概是抽象類惟一的優勢。
若是向一個抽象類加入一個新的具體方法,那麼全部的子類型一會兒就都獲得獲得了這個新的具體方法,而接口作不到這一點。
簡短的表述:要儘可能使用合成/聚合,儘可能不要使用繼承。
ref: 談一談本身對依賴、關聯、聚合和組合之間區別的理解【有代碼示範】
ref: 類與類之間的幾種關係
[總結]
對於繼承、實現這兩種關係沒多少疑問,它們體現的是一種類和類、或者類與接口間的縱向關係。其餘的四種關係體現的是類和類、或者類與接口間的引用、橫向關係,是比較難區分的,有不少事物間的關係要想準肯定位是很難的。前面也提到,這四種關係都是語義級別的,因此從代碼層面並不能徹底區分各類關係,但總的來講,後幾種關係所表現的強弱程度依次爲:組合>聚合>關聯>依賴。
若 需使用一個類的方法,能夠經過 繼承 或者 聚合/組合。
優前後者,下降耦合。
既然 getConnection() 可能會變化,那麼其所在的類 不便成爲基類(Base Class),
而後 採用 構造函數注入、setter方法注入 和 接口注入。從而注入不一樣的數據庫。
Reference: Sprint IOC 三種注入方法
控制反轉 (Inverse Of Control)
/* 難理解,往後再說 */
控制反轉是一種將 組件依賴關係 的 建立和管理 置於程序外部的技術。
由容器控制程序之間的關係,而不是由代碼直接控制。
因爲控制權由代碼轉向了容器,因此稱爲反轉。
Dependency Injection:兩個對象之間的依賴關係在程序運行時由外部容器動態的注入依賴行爲方式稱爲依賴注入 (DI) 。 DI 是 IOC 的一種形式。
依賴注入的三種實現類型:接口注入、 Setter注入和構造器注入。
接口注入
public class ClassA { private InterfaceB clzB; public void doSomething()
{ Ojbect obj = Class.forName(Config.BImplementation).newInstance(); clzB = (InterfaceB)obj; clzB.doIt() } …… }
set注入
public class ClassA { private InterfaceB clzB; public void setClzB(InterfaceB clzB) { this. clzB = clzB; } …… }
構造器注入
public class DIByConstructor { private final DataSource dataSource; public DIByConstructor(DataSource ds)
{ this.dataSource = ds; } …… }
面向切面 (Aspect Oriented Programming)
???
/* implement */
/* 一個軟件實體應當儘量少地與其餘實體發生相互做用 */
添加中間類來下降界面組件之間的耦合度.
一個對象應當對其餘對象有儘量少的了了解,爲了下降耦合度。
Ref: 類與類之間的幾種關係
繼承指的是一個類(稱爲子類、子接口)繼承另外的一個類(稱爲父類、父接口)的功能,並能夠增長它本身的新功能的能力。在Java中繼承關係經過關鍵字extends明確標識,在設計時通常沒有爭議性。在UML類圖設計中,繼承用一條帶空心三角箭頭的實線表示,從子類指向父類,或者子接口指向父接口。
實現指的是一個class類實現interface接口(能夠是多個)的功能,實現是類與接口之間最多見的關係。在Java中此類關係經過關鍵字implements明確標識,在設計時通常沒有爭議性。在UML類圖設計中,實現用一條帶空心三角箭頭的虛線表示,從類指向實現的接口。
【做爲了參數而使用】
簡單的理解,依賴就是一個類A使用到了另外一個類B,而這種使用關係是具備偶然性的、臨時性的、很是弱的,可是類B的變化會影響到類A。好比某人要過河,須要借用一條船,此時人與船之間的關係就是依賴。表如今代碼層面,爲類B做爲參數被類A在某個method方法中使用。在UML類圖設計中,依賴關係用由類A指向類B的帶箭頭虛線表示。
關聯體現的是兩個類之間語義級別的一種強依賴關係,好比我和個人朋友,這種關係比依賴更強、不存在依賴關係的偶然性、關係也不是臨時性的,通常是長期性的,並且雙方的關係通常是平等的。關聯能夠是單向、雙向的。表如今代碼層面,爲被關聯類B以類的屬性形式出如今關聯類A中,也多是關聯類A引用了一個類型爲被關聯類B的全局變量。在UML類圖設計中,關聯關係用由關聯類A指向被關聯類B的帶箭頭實線表示,在關聯的兩端能夠標註關聯雙方的角色和多重性標記。
聚合是關聯關係的一種特例,它體現的是總體與部分的關係,即has-a的關係。此時總體與部分之間是可分離的,它們能夠具備各自的生命週期,部分能夠屬於多個總體對象,也能夠爲多個總體對象共享。好比計算機與CPU、公司與員工的關係等,好比一個航母編隊包括海空母艦、驅護艦艇、艦載飛機及核動力攻擊潛艇等。表如今代碼層面,和關聯關係是一致的,只能從語義級別來區分。在UML類圖設計中,聚合關係以空心菱形加實線箭頭表示。
組合也是關聯關係的一種特例,它體現的是一種contains-a的關係,這種關係比聚合更強,也稱爲強聚合。它一樣體現總體與部分間的關係,但此時總體與部分是不可分的,總體的生命週期結束也就意味着部分的生命週期結束,好比人和人的大腦。表如今代碼層面,和關聯關係是一致的,只能從語義級別來區分。在UML類圖設計中,組合關係以實心菱形加實線箭頭表示。
軟件模式: 設計模式、體系結構模式、分析模式、過程模式等。
ANSIIEEEStd1471一200對體系結構的定義:一個系統的基本組織,表現爲系統的組件、組件之間的相互關係、組件和環境之間的相互關係以及設計和進化的原則。
黑板模式是一種經常使用的架構模式,應用中的多種不一樣數據處理邏輯相互影響和協同來完成數據分析處理。
「就好像多位不一樣的專家在同一黑板上交流思想,每一個專家均可以得到別的專家寫在黑板上的信息,同時也能夠用本身的分析去更新黑板上的信息,從而影響其它專家。」
數據庫模式
發佈—訂閱模式 (難點)
1) 一個 delegate對象一次能夠搭載多個方法(methods),而不是一次一個。當咱們喚起一個搭載了多個方法(methods)的delegate,全部方法以其「被搭載到delegate對象的順序」被依次喚起。
2) 一個delegate對象所搭載的方法(methods)並不須要屬於同一個類別。一個delegate對象所搭載的全部方法(methods)必須具備相同的原型和形式。然而,這些方法(methods)能夠即有static也有non-static,能夠由一個或多個不一樣類別的成員組成。
3) 一個delegate type的聲明在本質上是建立了一個新的subtype instance,該 subtype 派生自 .NET library framework 的 abstract base classes Delegate 或 MulticastDelegate,它們提供一組public methods用以詢訪delegate對象或其搭載的方法(methods) ,與函數指針不一樣,委託是面向對象、類型安全而且安全的。
爲了實現P與S.P, S與S.P之間的解耦,咱們須要定義兩個接口文件:
ISubscribe.cs
namespace TJVictor.DesignPattern.SubscribePublish { //定義訂閱事件 public delegate void SubscribeHandle(string str); //定義訂閱接口 public interface ISubscribe { event SubscribeHandle SubscribeEvent; } }
IPublish.cs namespace TJVictor.DesignPattern.SubscribePublish { //定義發佈事件 public delegate void PublishHandle(string str); //定義發佈接口 public interface IPublish { event PublishHandle PublishEvent; void Notify(string str); } }
而後咱們來設計訂閱器。顯然訂閱器要實現雙向解耦,就必定要繼承上面兩個接口,這也是我爲何用接口不用抽象類的緣由(類是單繼承)。
namespace TJVictor.DesignPattern.SubscribePublish { public class SubPubComponet : ISubscribe, IPublish { private string _subName; public SubPubComponet(string subName) { this._subName = subName; PublishEvent += new PublishHandle(Notify); } #region ISubscribe Members
event SubscribeHandle subscribeEvent; event SubscribeHandle ISubscribe.SubscribeEvent { add { subscribeEvent += value; } remove { subscribeEvent -= value; } } #endregion
#region IPublish Members
public PublishHandle PublishEvent; event PublishHandle IPublish.PublishEvent { add { PublishEvent += value; } remove { PublishEvent -= value; } } #endregion
public void Notify(string str) { if (subscribeEvent != null) subscribeEvent.Invoke(string.Format("消息來源{0}:消息內容:{1}", _subName, str)); }
} }
接下來是設計訂閱者S。S類中使用了ISubscribe來與S.P進行解耦。代碼以下:
namespace TJVictor.DesignPattern.SubscribePublish { public class Subscriber { private string _subscriberName; public Subscriber(string subscriberName) { this._subscriberName = subscriberName; } public ISubscribe AddSubscribe { set { value.SubscribeEvent += Show; } } public ISubscribe RemoveSubscribe { set { value.SubscribeEvent -= Show; } } private void Show(string str) { Console.WriteLine(string.Format("我是{0},我收到訂閱的消息是:{1}", _subscriberName, str)); } } }
最後是發佈者P,繼承IPublish來對S.P發佈消息通知。
namespace TJVictor.DesignPattern.SubscribePublish { public class Publisher:IPublish { private string _publisherName; public Publisher(string publisherName) { this._publisherName = publisherName; } private event PublishHandle PublishEvent; event PublishHandle IPublish.PublishEvent { add { PublishEvent += value; } remove { PublishEvent -= value; } } public void Notify(string str) { if (PublishEvent != null) PublishEvent.Invoke(string.Format("我是{0},我發佈{1}消息", _publisherName, str)); } } }
至此,一個簡單的訂閱發佈模式已經完成了。下面是調用代碼及運行結果。調用代碼模擬了圖2中的訂閱發佈關係,你們能夠從代碼,運行結果和示例圖三方面對照着看。
#region TJVictor.DesignPattern.SubscribePublish //新建兩個訂閱器 SubPubComponet subPubComponet1 = new SubPubComponet("訂閱器1"); SubPubComponet subPubComponet2 = new SubPubComponet("訂閱器2"); //新建兩個發佈者 IPublish publisher1 = new Publisher("TJVictor1"); IPublish publisher2 = new Publisher("TJVictor2"); //與訂閱器關聯 --> 訂閱器 監聽 發佈者? publisher1.PublishEvent += subPubComponet1.PublishEvent; publisher1.PublishEvent += subPubComponet2.PublishEvent; publisher2.PublishEvent += subPubComponet2.PublishEvent; //新建兩個訂閱者 Subscriber s1 = new Subscriber("訂閱人1"); Subscriber s2 = new Subscriber("訂閱人2"); //進行訂閱 s1.AddSubscribe = subPubComponet1; s1.AddSubscribe = subPubComponet2; s2.AddSubscribe = subPubComponet2; /***********************************************************/ //發佈者發佈消息 publisher1.Notify("博客1"); publisher2.Notify("博客2"); //發送結束符號 Console.WriteLine("".PadRight(50,'-')); //s1取消對訂閱器2的訂閱 s1.RemoveSubscribe = subPubComponet2; //發佈者發佈消息 publisher1.Notify("博客1"); publisher2.Notify("博客2"); //發送結束符號 Console.WriteLine("".PadRight(50, '-')); #endregion #region Console.ReadLine(); Console.ReadLine(); #endregion
在知足對界面要求的同時,如何使軟件的計算模型獨立於界面的構成。
還有PAC(Presentation-Abstraction-Control)、Forward-Receiver、Publisher-Subscriber、各種可視化用戶界面控件等。
Reference: 軟件分析模式的形式化研究, 鍾琪, 西南師範大學
分析模式是更高層次的抽象。與測試模式不一樣,分析模式不反應實際的軟件實現,而是體現行業業務過程的概念結構。
按用途能夠劃分爲:Accountability, Observations and measurements, Observations for Corporate finance, Referring to Objects, Inventory, Planning, trading.
Example: Party in Accountability
Reference: http://www.cnblogs.com/houleixx/archive/2009/10/20/software-engineering-process-model.html
軟件過程是爲了得到高質量軟件所須要完成的一系列任務的框架,它規定了完成各項任務的工做步驟。
一般使用生命週期模型簡潔地描述軟件過程。生命週期模型規定了把生命週期劃分紅哪些階段及各個階段的執行順序,所以,也稱爲過程模型。
常見的過程模型有瀑布模型、快速原型模型、增量模型、螺旋模型、噴泉模型等。
設計模式是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結,使用設計模式的目的是提升代碼的可重用性,讓代碼更容易被他人理解,並保證代碼可靠性。它是代碼編制真正實現工程化。
詳見以後的篇章,加油。
知名博客:http://www.javashuo.com/article/p-aljiukeo-gd.html
菜鳥教程:http://www.runoob.com/design-pattern/design-pattern-tutorial.html
End.