成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

軟件開發必修課:你該知道的GRASP職責分配模式

開發 開發工具
軟件在本質上是復雜的,軟件本身的復雜性在于除了要解決問題域,還要解決非功能性需求和軟件域特有問題:安全性、可用性、可維護性、可擴展性、性能、一致性、容錯性、穩定性、可重用性、冪等、兼容等等,軟件開發者的任務就是制造“簡單”的假象。

軟件在本質上是復雜的,軟件本身的復雜性在于除了要解決問題域,還要解決非功能性需求和軟件域特有問題:安全性、可用性、可維護性、可擴展性、性能、一致性、容錯性、穩定性、可重用性、冪等、兼容等等,軟件開發者的任務就是制造“簡單”的假象。如何組織復雜的系統?把復雜的事物分解到不同的層次中,層次代表了不同級別的抽象,一層構建于另一層之上,每一層都對上層屏蔽內部復雜度。

一 為什么使用RDD?

在RDD中,我們認為“軟件對象具有職責”,這個定義很符合人在社會群體中分工協作的方式,軟件也是人編寫的,所以根據職責思考設計的軟件系統符合人的行為習慣,同時更易于理解和管理。在微服務架構中不同系統由不同的組織和人負責,把系統當作對象(人),系統提供的接口就是對象(人)的職責。

職責驅動設計的核心是考慮怎樣給對象分配職責,其適用于大到系統、小到對象等任何規模的軟件。職責分配的本質是分工,勞動分工是勞動生產率提高的主要原因。

  • 熟練度的提高,專注于某個領域(降低復雜度)。
  • 時間的節約,同一個人在不同工作來回切換需要耗費大量時間。
  • 人工發明的機器和應用(特定領域的工具)。

二 如何給對象(元素)分配職責?

分配職責應當從清晰的描述職責開始,對于軟件領域對象來說,領域模型描述了領域對象的屬性和關聯,對應類的屬性和引用,用例模型包含一系列的行為活動,對應類的方法。領域模型創建方式可參考《UML和模式應用》、UDD、DDD。

使用GRASP(General Responsibility Assignment Software Patterns)模式分配職責,GRASP是通用職責分配模式,是對一些基本的職責分配原則進行了命名和描述,共9種模式(一些GRASP原則是對其他原則和設計模式的歸納,設計模式有上百種,只是記住GoF 23種設計模式就已經很困難了,更別提還要記住每種模式的細節,因此需要對設計模式進行有效的歸類。GRASP中的原則描述了模式的本質,除了有助加速設計模式學習之外,對發現現有設計存在的問題也更有效,這就是歸納的價值)。

當談論低耦合、高內聚時,我們具體是在談什么?問題不在于耦合度高、內聚性低,而是在于其產生的負面影響,負面影響往往是在發生變化時體現出來的,這些負面影響會影響到我們開發的效率、穩定性、可維護性、可擴展性、可復用性等等,整個GRASP的核心是如何防止變異(變化)。

在學習過程中發現GRASP缺少結構化的展示歸納結果,通過我自己的理解把開發中常用的GoF設計模式、面向對象設計原則、架構設計原則和GRASP進行關聯:

 

??

??


注:這個圖可能總結的還不夠準確,正在逐步學習修改。

 

 

三 GRASP職責分配模式

1 防止變異

該模式基本等同于信息隱藏和開閉原則。如何做到在不修改原來功能的前提下對變化的部分進行擴展?識別不穩定因素是特別困難的,也決定了我們能否做出符合開閉原則的設計。

問題:如何設計對象、子系統和系統,使其內部的變化或不穩定性不會對其他元素產生不良影響。

解決方案:識別預計變化或不穩定之處,分配職責用以在這些變化之外創建穩定接口。

相關原則和模式:

  • GRASP:間接性、多態
  • GoF:大量模式
  • 其他:接口、數據封裝

2 低耦合、高內聚

耦合是對某元素與其他元素之間的連接、感知和依賴程度的度量,內聚是對元素職責的相關性和集中度的度量(這里的元素指類、系統、子系統等等),耦合和內聚是從不同角度看待問題,他們互相依賴的互相影響的(以下兩點也可以反過來說):

  • 內聚過低,相關功能分散在不同模塊中,需要增加額外的耦合使這些功能聚合在一起,發生變更時影響多個模塊。
  • 內聚過高,不相關的功能聚集在一個模塊中,耦合度高,發生變更時會產生意想不到的影響。

??

??

 

低耦合

耦合是對某元素與其他元素之間的連接、感知和依賴程度的度量。這里的元素指類、系統、子系統等等。

問題:怎樣降低依賴性,減少變化帶來的影響,提高重用性?

解決方案:分配職責,使耦合盡可能低。利用這一原則評估可選方案。

相關模式或原則:

  • GRASP:防止變異

注意:耦合不能脫離專家、高內聚等其他原則獨立考慮。

緊密耦合的系統在開發階段有以下的缺點:

  • 一個模塊的修改會產生漣漪效應,其他模塊也需隨之修改(通常是內聚低引起的)。
  • 由于模塊之間的相依性,模塊的組合會需要更多的精力及時間,可復用性低(通常是耦合高引起的)。

解讀:耦合表示元素之間存在依賴,當談論“耦合高”時,我們具體是在談論什么呢?是依賴產生的負面影響,所以低耦合的核心是解決不良依賴。高低是度量并不是評判耦合結果好壞的標準,使用“不良耦合”、“松耦合”描述的更為準確。不良耦合產生的負面影響主要有兩點:

  • 依賴關系本身錯綜復雜難以維護和理解,很容易產生遺漏和問題(這點針對人,人處理復雜性事物時能力是局限的)。
  • 與不穩定元素產生依賴時很容易受到變化的影響(通常無法避免不依賴)。

那么如何做呢?先對依賴關系的好壞進行評估:依賴方式、依賴方向、依賴鏈路。

??

??

 

方向:

  • 雙向依賴(差)
  • 相互依賴的兩個元素不能獨立行動,在微服務系統架構的系統中類級別不會產生特別復雜的問題,但是在模塊 or 系統級別就特別容易受到變化帶來的影響。
  • 舉例:A <-> B,A調用B的b接口,B的b接口依賴A的a接口,如果a b接口都要變更,兩個系統如何發布?A依賴B先發布,B也依賴A先發布,相互依賴的兩個元素不能獨立行動。
  • 循環依賴(更差)
  • 循環依賴比雙向依賴的的鏈路更長,影響的范圍更大。
  • 單向依賴(好)

鏈路:

  • 深度
  • B調用A.getC().getD().getE().getF() 獲取到F。
  • 廣度
  • 在鏈路變寬的過程中不加以約束和管理很容易產生大雜燴的元素,也很容易產生雙向和循環依賴。

方式:

  • 內容耦合(高)
  • 當一個模塊直接使用另一個模塊的內部數據,或通過非正常入口而轉入另一個模塊內部。
  • 共享耦合/公共耦合(高)
  • 指通過一個公共數據環境相互作用的那些模塊間的耦合。
  • 公共耦合的復雜程度隨耦合模塊的個數增加而增加。
  • 控制耦合(中)
  • 指一個模塊調用另一個模塊時,傳遞的是控制變量(如開關、標志等),被調模塊通過該控制變量的值有選擇地執行塊內某一功能;
  • 特征耦合/標記耦合(中)
  • 指幾個模塊共享一個復雜的數據結構,如高級語言中的數組名、記錄名、文件名等這些名字即標記,其實傳遞的是這個數據結構的地址;
  • 數據耦合(低)
  • 指模塊借由傳入值共享數據,每一個數據都是最基本的數據,而且只分享這些數據(例如傳遞一個整數給計算平方根的函數)。
  • 非直接耦合(低)
  • 兩個模塊之間沒有直接關系,它們之間的聯系完全是通過主模塊的控制和調用來實現的。耦合度最弱,模塊獨立性最強。
  • 無耦合(無)
  • 模塊完全不和其他模塊交換信息。

解決不良依賴:

  • 管理復雜的依賴關系
  • 依賴方向:使用單向依賴,去除或弱化雙向依賴,不使用循環依賴。
  • 依賴鏈路:遵守最少認知原則。
  • 依賴方式:盡量使用數據耦合,少用控制和特征耦合,控制公共耦合的范圍,不使用內容耦合,如果依賴的對象不穩定使用非直接耦合來弱化耦合緊密程度。
  • 分配正確的職責減少不必要的依賴:專家、創建者。
  • 通過其他原則和模式減少不穩定元素帶來的影響:高內聚、純虛構、控制器、多態、間接性、最少認知。

高內聚

內聚是對元素職責的相關性和集中度的度量。

問題:怎么樣保持對象是有重點的、可理解的、可維護的,并且能夠支持低耦合?

解決方案:按照相關性分配職責,可保持較高的內聚。

優點:

  • 分解后的元素更加簡單易于理解和維護。
  • 按照相關性拆分可以提高重用性。

相關原則和模式:單一職責原則、關注點分離、模塊化。

低內聚的缺點:內聚性較低的類要做許多不相關的工作,或需要完成大量的工作,這樣的類會導致以下問題:

  • 難以理解
  • 難以復用
  • 難以維護
  • 經常會受到變化影響

??

??

 

例子:A的變更影響從3個模塊變為1個。

??

??

 

小結

通過結構化管理來保持低耦合、高內聚。

??

??

 

3 創建者

創建者指導我們分配那些與創建對象有關的職責。如此選擇是為了保持低耦合。

問題:誰應該負責創建某類的新實例?

解決方案:滿足以下條件之一時,將創建類A的職責分配給類B(當滿足1條以上時,通常首選包含或聚合)。

  • B“包含”或聚合A。
  • B記錄A。
  • B頻繁使用A。
  • B具有A的初始化數據,該數據將在創建時傳遞給A。

優點:支持低耦合,因為創建者和被創建者已經存在關聯,所以這種方式不會增加耦合性。

相關模式或原則:

  • GRASP:低耦合
  • GoF:具體工廠、抽象工廠
  • 其他:整體-部分

注:包含(作者在這里標注了“”,因為包含在uml是表達用例關系的,用來說明對象關系也可以)、聚合、整體-部分 看UML定義;包含強調了強依賴(A是B的子集,A屬于B,缺少了A時B不是整體),聚合是弱依賴(B由A組成,A不屬于B)。

例子:

??

??

 

  • Order包含Goods(Order脫離Goods就失去了完整性,沒有存在的意義)。
  • Order記錄相關的Goods。
  • Goods初始化數據:
  • 情況一:只需要訂單上的Goods數據,這種情況Order具有Goods的初始化數據。
  • 情況二:訂單上的Goods數據不完整,這種情況Order只有Goods初始化數據的一小部分,Order不能做為創建者。

4 信息專家(or 專家)

“信息”不單指數據。

問題:給對象分配職責的基本原則是什么?

解決方案:把職責分配給信息專家,它具有實現這個職責所必需的信息

優點:

  • 對象使用自身信息來完成任務,所以信息的封裝性得以維持,因此支持了低耦合(至少不會增加耦合性)。
  • 行為分布在那些具有所需信息的類之間,這樣功能更集中,因此支持了高內聚。

相關模式或原則:

  • GRASP:低耦合、高內聚

注意:和“關注點分離”一起使用使得對象進一步內聚,從而達到高內聚,也能降低耦合。

舉例:獲取所有買的商品總金額,Order和Goods是一對多的關系。

??

??

 

分析:Order本身關聯了Goods,并且理解Goods的結構。在圖例中Client通過Order獲取了Goods并做了邏輯運算得出商品總金額,這種做法產生了不必要的依賴增加了耦合數量,商品總金額計算的職責由Order承擔最合適。

??

??

 

延伸:在某些情況下,該方案并不合適,通常是由于耦合與內聚問題產生的,如:誰應該把對象A存入數據庫?按照原則每個類都應該具有把自己持久化的能力。

5 純虛構

為了保持良好的耦合和內聚,捏造業務上不存在的對象來承擔職責。

問題:當你并不想違背高內聚和低耦合或者其他目標,但是基于專家模式所提供的方案又不合適時,哪些對象應該承擔這一職責?

解決方案:對人為制造的類分配一組高內聚的職責,該類并不代表問題領域的概念--虛構的事物,用以支持高內聚、低耦合和復用。

優點:

  • 支持高內聚,因為職責被解析為細粒度的類,這種類只著重于極為特定的一組相關任務。
  • 增加了潛在的復用性。

相關原則和模式:

  • GRASP:低耦合、高內聚。
  • 通常接納本來是基于專家模式所分配給領域類的職責。
  • 所有GoF設計模式都是純虛構,事實上所有其他設計模式也都是純虛構。

舉例:計算商品總數量。根據專家模式計算商品總數量的職責也應該是分配給Order,照這樣分配下去商品相關的還會有:總重量、總體積、總XX,這時Order的職責就會越來越多也可能會產生額外的耦合,通過純虛構對象把這些職責分配出去能夠得到更好的設計。

??

??

 

通過虛構對象GoodsItems承擔和商品聚合計算相關的職責。

延伸:經常發現代碼中會使用Util、Handler、Service這樣的虛構類,缺點是這些類通常是單例并共用的,這些虛構類的職責會越來越多(一個Util類2000行代碼),創建和業務更相近的虛構對象才能便于理解和管理耦合關系。

6 控制器

解決方案:把職責分配給能代表以下選擇之一的類:

  • 代表整個“系統”、“根對象”、運行軟件的設備或主要子系統,這些是外觀控制器的所有變體。
  • 代表用例場景,在該場景中發生系統事件。

相關模式:

  • GRASP:純虛構
  • GoF:命令、外觀
  • 其他:層

控制器的核心是提供一個統一入口,避免客戶對元素內部進行耦合,很好的維護了邊界:

  • api層
  • 根對象
  • 接口

7 多態

問題:如何處理給予類型的選擇?如何創建可插拔的軟件構件?

解決方案:當相關選擇或行為隨類型有所不同時,使用多態操作為變化的行為類型分配職責。

優點:可擴展性強,同時不影響客戶。

相關原則和模式:

  • GRASP:防止變異
  • GoF:大量模式

訂單退款時需要計算出用戶退款金額和商戶扣款金額,在沒有新零售業務進來之前直接使用計算服務返回的數據結構,新零售進來后數據結構未統一,需要進行適配,實現多態后的代碼擴展性很強。

??

??

 

在微服務架構中,比較復雜的多態問題通常會選擇增加一層去解決,如:支付網關、交付網關。

8 間接性

計算機學科中的大多數問題都可以通過增加一層解決,如果不行再加一層。反過來大多數性能問題都可以通過去掉一層來解決。

問題:為了避免兩個或多個事物之間直接耦合,應該如何分配職責?

解決方案:將職責分配給中介對象,使其作為其他構建或服務之間的媒介,以避免他們之間的直接耦合。

優點:實現了構件之間的低耦合。

相關原則和模式:

  • GRASP:防止變異、低耦合、大量間接性中介都是純虛構
  • GoF:大量模式

注意:間接性通常用來支持防止變異。

四 架構模式

除了職責分配原則,還需要一些架構模式幫助我們更好的落地。

1 分層架構

在分布式系統中系統是獨立存在的,可以單獨變更而不對其他系統產生影響,但是隨著業務整體復雜度的提升也帶來了一些負面影響:由于整體被分解成大量獨立的系統,隨著復雜度提升系統之間的依賴關系會變的錯綜復雜,某個系統的變更會影響其他系統,同時也會產生意想不到的問題,效率也隨之下降。這時就需要重新對分布式系統的邏輯架構做設計,以解決系統間的不良耦合和內聚,從而提效。

分層架構是非常實用和常見的方式,TCP/IP、HTTP、操作系統等等都運用了分層,分層的本質很簡單:通過分離關注點,達到高內聚;通過向下依賴、拒絕循環依賴、使用接口,達到低耦合。

??

??

 

分層架構也是存在缺點的:按照分層架構定義消息消費應該在基礎設施層,但是消息消費是為了執行某個業務邏輯,這樣就需要依賴應用層 或 領域層,如果真的這樣寫就會出現循環依賴問題。通過依賴倒置可以解決依賴問題。

2 六(多)邊形架構(洋蔥圈架構)

六邊形架構(Hexagonal Architecture),又稱為端口和適配器架構風格,其中的“六”具體數字沒有特殊的含義,僅僅表示一個“量級”的意思,六邊形的定義只是方便更加形象的理解。

??

??

 

六邊形架構提倡用一種新的視角來看待整個系統,該架構中存在兩個區域:“外部區域”和“內部區域”。在外部區域中不同的客戶均可以提交輸入(網絡請求、定時腳本、消息消費等),而內部區域則是處理具體邏輯的地方。

??

??

圖源:https://www.jianshu.com/p/d3e8b9ac097b

 

五 案例

案例1:Jpa替換為Mybatis

@Component 
public class CloseOrderService {
@Autowired(required = false)
@Qualifier("rstOrderTransactionManager")
JpaTransactionManager tm;

public void invalid_order(Long orderId, Long userId, Short processGroup)
throws UserException, SystemException, UnknownException {
//其他邏輯。。。省略

// 開啟事務
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus ts = tm.getTransaction(def);

try {
order = orderDAO.get(orderId);
order.setStatusCode(toStatus);
order.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
orderDAO.save(order);
//提交事務
tm.commit(ts);
} catch (Exception e) {
if (!ts.isCompleted()) {
//回滾
tm.rollback(ts);
}
if (e instanceof SatisfiedStateException) {
return;
}
throw e;
}
}
@Transactional(transactionManager = "rstOrderTransactionManager", rollbackFor = Exception.class)
public void invalidOrder(){
}
}

@Component
public interface OrderDAO extends JpaRepository<OrderPO, Long> {
@Query(value = "sql語句", nativeQuery = true)
Long generateGlobalOrderId(@Param("userId") Long userId,
@Param("restaurantId") Long restaurantId,
@Param("seqName") String seqName);
}

變化帶來的影響:如果不出意外對Jpa的使用方式不會產生變更,意味著其相對穩定,所以在當前階段來看以上耦合是正常的也不會產生負面影響。但是在以下場景會讓我們對高耦合有很明顯的體感:大家覺得Jpa不好用,想替換為Mybatis該怎么做?代碼中直接使用了繼承JpaRepository的OrderDAO做數據操作,由于Jpa和Mybatis的寫法不同,所以需要把使用到OrderDAO的地方都做替換:

  • 調用OrderDAO的類(70多個類)都需要替換為新的dao。
  • 使用JpaTransactionManager.getTransaction()的位置需要替換為MyBatis的TransactionManager。
  • 使用@Transactional(transactionManager = "rstOrderTransactionManager")的位置需要改為編寫事務提交和回滾的代碼塊兒,便于做灰度。
  • 以上改動的位置需要增加開關做灰度。

結論:由于變更涉及到70多個類,同時事務管理器獲取方式也需要修改,其帶來的影響還是挺大的,不滿足“低耦合”原則,可以使用“多態”原則重新設計。

案例2:訂單對應的支付單應該由誰來創建?

拿餓了么交易系統舉例,當前創建支付單的職責是由bos服務承擔(面向app的一個后端服務)的,接下我們進行分析。

??

??

 

支付單創建分為兩種場景:

  • 創建訂單和支付單是在一次操作中完成。
  • 用戶回到訂單列表頁點擊“去支付”時創建支付單。

支付單創建依賴:

  • 訂單號
  • 支付金額
  • 支付類型
  • 一堆支付系統分配的用于識別業務的參數

??

??

 

注1:如果餓了么只會有外賣一種交易業務,當前的設計還是很穩定的,不會出現太大變化。所以識別變化點才能更好的評判當前系統設計是否合理,如:餓了么將升級為本地生活服務公司,根據公司戰略多少能看出我們將來不只外賣業務存在,還會有很多和本地生活相關的交易業務,這些業務會有自己的展示層(app、h5、web)同時對應會有類似bos的服務,如果有10個業務方,在支付場景就需要去對接10次,而由order做就只需要一次(支付作為工具已經比較穩定,不會有太大變化)。

  • bos比order多出識別訂單結構的成本。
  • bos比order多出認知交易域業務知識的成本。需要深入了解交易狀態,這樣才知道什么狀態才能去支付(一般是去問order服務的開發),打破了邊界。

結論:bos服務不應該承擔創建支付單的職責,由order承擔最合適。

【本文為51CTO專欄作者“阿里巴巴官方技術”原創稿件,轉載請聯系原作者】

??戳這里,看該作者更多好文??

 

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2009-09-29 10:35:42

Linux系統系統提速Linux

2015-07-29 10:25:05

數據開發產品必修課

2010-11-25 10:55:34

2014-02-17 09:22:37

2022-03-11 10:53:32

UML建模語言

2009-02-10 15:08:41

2012-01-06 14:10:42

數據質量管理大數據數據管理

2023-09-27 22:18:41

2022-08-15 15:03:57

數字化轉型數字技術中小企業

2018-04-28 10:05:17

2025-06-10 08:05:00

錯誤返回GoAPI

2020-01-13 16:26:57

AI人工智能機器

2014-06-23 15:37:50

2023-09-12 11:28:10

2017-04-12 09:24:45

開發編程Java

2013-02-28 09:46:18

程序員巖機Hacker News

2022-09-19 10:04:44

人工智能AIIT領導者

2025-02-05 11:00:00

開發Java對象模型

2021-05-11 10:12:06

CIO軟件開發首席信息官
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲人在线 | 国产精品国产a级 | 日韩免费一区 | 国产福利视频在线观看 | 日本 欧美 国产 | 精品久久久久久久久久久久 | 99精品久久久久 | 性生生活大片免费看视频 | 精品欧美一区二区三区久久久 | 日韩欧美一二三区 | 成人一区二区三区在线观看 | 国产日韩欧美精品一区二区三区 | wwwxxx国产 | 久久久天堂 | 国产婷婷综合 | 国产精品日韩在线观看 | 国产欧美精品一区二区色综合朱莉 | 亚洲免费观看视频 | 91久久视频| 国产成人精品在线 | 国产精品久久久久久久 | 午夜成人在线视频 | 一级片在线观看 | 中文字幕第二区 | 天天操天天射天天 | 精品欧美一区二区三区精品久久 | 99爱国产 | 国产wwwcom| 久久成人18免费网站 | 国产精品视频一区二区三区 | 一本大道久久a久久精二百 国产成人免费在线 | 91在线电影| 国产99免费视频 | 亚洲精品久久久久久久久久久 | 激情 一区 | 国产视频1区 | 精品伦精品一区二区三区视频 | 精品国产欧美一区二区三区成人 | 欧美精品成人影院 | 久久成人精品视频 | 青青草中文字幕 |