|
引言
軟件系統(tǒng)面向?qū)ο蟮脑O(shè)計思想可謂歷史悠久,20世紀(jì)70年代的Smalltalk可以說是面向?qū)ο笳Z言的經(jīng)典,直到今天我們依然將這門語言視為面向?qū)ο笳Z言的基礎(chǔ)。隨著編程語言和技術(shù)的發(fā)展,各種語言特性層出不窮,面向?qū)ο笫谴蟛糠终Z言的一個基本特性,像C++、Java、C#這樣的靜態(tài)語言,Ruby、Python這樣的動態(tài)語言都是面向?qū)ο蟮恼Z言。
但是面向?qū)ο笳Z言并不是銀彈,如果開發(fā)人員認(rèn)為使用面向?qū)ο笳Z言寫出來的程度本身就是面向?qū)ο蟮模蔷痛箦e特錯了。實際開發(fā)中,大量的業(yè)務(wù)邏輯堆積在一個巨型類中的例子屢見不鮮,代碼的復(fù)用性和擴展性無法得到保證。為了解決這樣的問題,領(lǐng)域驅(qū)動設(shè)計提出了清晰的分層架構(gòu)和領(lǐng)域?qū)ο蟮母拍睿屆嫦驅(qū)ο蟮姆治龊驮O(shè)計進(jìn)入了一個新的階段,對企業(yè)級軟件開發(fā)起到了巨大的推動作用。
本文主要介紹了領(lǐng)域驅(qū)動設(shè)計的基本概念、要素、特點,對比了事務(wù)腳本和領(lǐng)域模型的特點,最后介紹了我們在軟件開發(fā)過程中的領(lǐng)域驅(qū)動設(shè)計實踐。
什么是領(lǐng)域驅(qū)動設(shè)計(DDD)
2004年著名建模專家Eric Evans發(fā)表了他最具影響力的書籍:《Domain-Driven Design: Tackling Complexity in the Heart of Software》(中文譯名:領(lǐng)域驅(qū)動設(shè)計:軟件核心復(fù)雜性應(yīng)對之道),書中提出了領(lǐng)域驅(qū)動設(shè)計(簡稱 DDD)的概念。
領(lǐng)域驅(qū)動設(shè)計事實上是針對OOAD的一個擴展和延伸,DDD基于面向?qū)ο蠓治雠c設(shè)計技術(shù),對技術(shù)架構(gòu)進(jìn)行了分層規(guī)劃,同時對每個類進(jìn)行了策略和類型的劃分。
領(lǐng)域模型是領(lǐng)域驅(qū)動的核心。采用DDD的設(shè)計思想,業(yè)務(wù)邏輯不再集中在幾個大型的類上,而是由大量相對小的領(lǐng)域?qū)ο?類)組成,這些類具備自己的狀態(tài)和行為,每個類是相對完整的獨立體,并與現(xiàn)實領(lǐng)域的業(yè)務(wù)對象映射。領(lǐng)域模型就是由這樣許多的細(xì)粒度的類組成。基于領(lǐng)域驅(qū)動的設(shè)計,保證了系統(tǒng)的可維護性、擴展性和復(fù)用性,在處理復(fù)雜業(yè)務(wù)邏輯方面有著先天的優(yōu)勢。
領(lǐng)域驅(qū)動設(shè)計的特點
領(lǐng)域驅(qū)動的核心應(yīng)用場景就是解決復(fù)雜業(yè)務(wù)的設(shè)計問題,其特點與這一核心主題息息相關(guān):
- 分層架構(gòu)與職責(zé)劃分:領(lǐng)域驅(qū)動設(shè)計很好的遵循了關(guān)注點分離的原則,提出了成熟、清晰的分層架構(gòu)。同時對領(lǐng)域?qū)ο筮M(jìn)行了明確的策略和職責(zé)劃分,讓領(lǐng)域?qū)ο蠛同F(xiàn)實世界中的業(yè)務(wù)形成良好的映射關(guān)系,為領(lǐng)域?qū)<遗c開發(fā)人員搭建了溝通的橋梁。
- 復(fù)用:在領(lǐng)域驅(qū)動設(shè)計中,領(lǐng)域?qū)ο笫呛诵模總€領(lǐng)域?qū)ο蠖际且粋€相對完整的內(nèi)聚的業(yè)務(wù)對象描述,所以可以形成直接的復(fù)用。同時設(shè)計過程是基于領(lǐng)域?qū)ο蠖皇腔跀?shù)據(jù)庫的Schema,所以整個設(shè)計也是可以復(fù)用的。
- 使用場景:適合具備復(fù)雜業(yè)務(wù)邏輯的軟件系統(tǒng),對軟件的可維護性和擴展性要求比較高。不適用簡單的增刪改查業(yè)務(wù)。
如果不使用DDD?
面對復(fù)雜的業(yè)務(wù)場景和需求,如果沒有建立和實現(xiàn)領(lǐng)域模型,會導(dǎo)致應(yīng)用架構(gòu)出現(xiàn)胖服務(wù)層和貧血的領(lǐng)域模型,在這樣的架構(gòu)中,Service層開始積聚越來越多的業(yè)務(wù)邏輯,領(lǐng)域?qū)ο髣t成為只有g(shù)etter和setter方法的數(shù)據(jù)載體。這種做法還會導(dǎo)致領(lǐng)域特定業(yè)務(wù)邏輯和規(guī)則散布于多個的Service類中,有些情況下還會出現(xiàn)重復(fù)的邏輯。我們曾經(jīng)見過5000多行的Service類,上百個方法,代碼基本上是不可讀的。
在大多數(shù)情況下,貧血的領(lǐng)域模型沒有成本效益。它們不會給公司帶來超越其它公司的競爭優(yōu)勢,因為在這種架構(gòu)里要實現(xiàn)業(yè)務(wù)需求變更,開發(fā)并部署到生產(chǎn)環(huán)境中去要花費太長的時間。
領(lǐng)域驅(qū)動設(shè)計的分層架構(gòu)和構(gòu)成要素
下面我們簡單介紹一下領(lǐng)域驅(qū)動設(shè)計的分層架構(gòu)和構(gòu)成要素,這部分內(nèi)容在Eric Evans的書中有非常詳盡的描述,想要詳細(xì)了解的,最好去讀原版書籍。
下面這張圖是該書中著名的分層架構(gòu)圖,如下:
整個架構(gòu)分為四層,其核心就是領(lǐng)域?qū)樱―omain),所有的業(yè)務(wù)邏輯應(yīng)該在領(lǐng)域?qū)訉崿F(xiàn),具體描述如下:
用戶界面/展現(xiàn)層 | 負(fù)責(zé)向用戶展現(xiàn)信息以及解釋用戶命令。 |
應(yīng)用層 | 很薄的一層,用來協(xié)調(diào)應(yīng)用的活動。它不包含業(yè)務(wù)邏輯。它不保留業(yè)務(wù)對象的狀態(tài),但它保有應(yīng)用任務(wù)的進(jìn)度狀態(tài)。 |
領(lǐng)域?qū)? | 本層包含關(guān)于領(lǐng)域的信息。這是業(yè)務(wù)軟件的核心所在。在這里保留業(yè)務(wù)對象的狀態(tài),對業(yè)務(wù)對象和它們狀態(tài)的持久化被委托給了基礎(chǔ)設(shè)施層。 |
基礎(chǔ)設(shè)施層 | 本層作為其他層的支撐庫存在。它提供了層間的通信,實現(xiàn)對業(yè)務(wù)對象的持久化,包含對用戶界面層的支撐庫等作用。 |
領(lǐng)域驅(qū)動設(shè)計除了對系統(tǒng)架構(gòu)進(jìn)行了分層描述,還對對象(Object)做了明確的職責(zé)和策略劃分:
- 實體(Entities):具備唯一ID,能夠被持久化,具備業(yè)務(wù)邏輯,對應(yīng)現(xiàn)實世界業(yè)務(wù)對象。
- 值對象(Value objects):不具有唯一ID,由對象的屬性描述,一般為內(nèi)存中的臨時對象,可以用來傳遞參數(shù)或?qū)嶓w進(jìn)行補充描述。
- 工廠(Factories):主要用來創(chuàng)建實體,目前架構(gòu)實踐中一般采用IOC容器來實現(xiàn)工廠的功能。
- 倉庫(Repositories):用來管理實體的集合,封裝持久化框架。
- 服務(wù)(Services):為上層建筑提供可操作的接口,負(fù)責(zé)對領(lǐng)域?qū)ο筮M(jìn)行調(diào)度和封裝,同時可以對外提供各種形式的服務(wù)。
當(dāng)然,DDD中還提出了聚合和聚合根(Aggregate Root)的概念,不過我們在實踐過程發(fā)現(xiàn)聚合根有問題復(fù)雜化的傾向,用傳統(tǒng)的聚合、組合等概念去描述領(lǐng)域?qū)ο笾g的關(guān)系更容易理解,所以這里對這個概念就不做介紹了。
事務(wù)腳本和領(lǐng)域模型
Martin Fowler 2004年所著的企業(yè)應(yīng)用架構(gòu)模式(Patterns of Enterprise Application Architecture)中的第九章領(lǐng)域邏輯模式(Domain Logic Patterns)專門介紹了事務(wù)腳本(Transaction Script)和領(lǐng)域模型(Domain Model),理解這兩種模式對設(shè)計和構(gòu)建企業(yè)應(yīng)用軟件非常有幫助,所以有必要介紹一下。
事務(wù)腳本:
事務(wù)腳本的核心是過程,通過過程的調(diào)用來組織業(yè)務(wù)邏輯,每個過程處理來自表現(xiàn)層的單個請求。大部分業(yè)務(wù)應(yīng)用都可以被看成一系列事務(wù),從某種程度上來說,通過事務(wù)腳本處理業(yè)務(wù),就像執(zhí)行一條條SQL語句來實現(xiàn)數(shù)據(jù)庫信息的處理。事務(wù)腳本把業(yè)務(wù)邏輯組織成單個過程,在過程中直接調(diào)用數(shù)據(jù)庫,業(yè)務(wù)邏輯在服務(wù)(Service)層處理。
事務(wù)腳本模式可以簡單的通過UML圖表示成這樣:
由Action層處理UI層的動作請求,將Request中的數(shù)據(jù)組裝后傳遞給BusinessService,BS層做簡單的邏輯處理后,調(diào)用數(shù)據(jù)訪問對象進(jìn)行數(shù)據(jù)持久化,其中VO充當(dāng)了數(shù)據(jù)傳輸對象的作用,一般是貧血的POJO,只具備getter和setter方法,沒有狀態(tài)和行為。
事務(wù)腳本模式的特點是簡單容易理解,面向過程設(shè)計。對于少量邏輯的業(yè)務(wù)應(yīng)用來說,事務(wù)腳本模式簡單自然,性能良好,容易理解,而且一個事務(wù)的處理不會影響其他事務(wù)。不過缺點也很明顯,對于復(fù)雜的業(yè)務(wù)邏輯處理力不從心,難以保持良好的設(shè)計,事務(wù)之間的冗余代碼不斷增多,通過復(fù)制粘貼方式進(jìn)行復(fù)用。可維護性和擴展性變差。
領(lǐng)域模型:
領(lǐng)域模型的特點也比較明顯, 屬于面向?qū)ο笤O(shè)計,領(lǐng)域模型具備自己的屬性行為狀態(tài),并與現(xiàn)實世界的業(yè)務(wù)對象相映射。各類具備明確的職責(zé)劃分,領(lǐng)域?qū)ο笤刂g通過聚合和引用等關(guān)系配合解決實際業(yè)務(wù)應(yīng)用和規(guī)則。可復(fù)用,可維護,易擴展,可以采用合適的設(shè)計模型進(jìn)行詳細(xì)設(shè)計。缺點是相對復(fù)雜,要求設(shè)計人員有良好的抽象能力。
領(lǐng)域模型對應(yīng)的就是領(lǐng)域驅(qū)動設(shè)計中劃分的領(lǐng)域?qū)樱@里就不詳細(xì)討論了。
在實際的設(shè)計中,我們需要根據(jù)具體的需求選擇相應(yīng)的設(shè)計模式。具備復(fù)雜業(yè)務(wù)邏輯的核心業(yè)務(wù)系統(tǒng)適合使用領(lǐng)域模型,簡單的信息管理系統(tǒng)可以考慮采用事務(wù)腳本模式。
領(lǐng)域驅(qū)動設(shè)計實踐
下面主要講一下我們在構(gòu)建企業(yè)級應(yīng)用開發(fā)平臺中對DDD的實踐和擴展。
本人近年來一直在從事企業(yè)級應(yīng)用開發(fā)平臺的相關(guān)工作,GAP平臺是我們的一個軟件產(chǎn)品,用來解決企業(yè)級軟件開發(fā)過程中復(fù)用、快速開發(fā)和過程規(guī)范等問題。設(shè)計這樣一個平臺,從底層的框架上就應(yīng)該能夠支撐復(fù)雜業(yè)務(wù)邏輯的系統(tǒng)構(gòu)建,所以我們在大的架構(gòu)設(shè)計思路上采用了領(lǐng)域驅(qū)動設(shè)計的思路,并根據(jù)實際采用的技術(shù)和要實現(xiàn)的功能對DDD的四層架構(gòu)進(jìn)行了細(xì)化和實現(xiàn):
整個平臺采用了JavaEE的技術(shù)及其相關(guān)的開源框架。系統(tǒng)的核心業(yè)務(wù)邏輯由Domain層處理,其中的業(yè)務(wù)服務(wù)(BusinessService)負(fù)責(zé)處理某個相對內(nèi)聚的業(yè)務(wù)邏輯單元,同時對內(nèi)對外提供本地或遠(yuǎn)程的服務(wù)。
下面是對各層的簡要描述:
- View:展示層,由于GAP平臺主要面向B/S架構(gòu),展示層主要由web資源文件組成,包括JSP,JS和大量的界面控件,同時還采用了AJAX和Flex等RIA技術(shù),負(fù)責(zé)向用戶展現(xiàn)豐富的界面信息,并執(zhí)行用戶的命令。
- Control:控制層,負(fù)責(zé)展示層請求的轉(zhuǎn)發(fā)、調(diào)度和基礎(chǔ)驗證,同時自動攔截后臺返回的Runtime異常信息,如果控制層需要與第三方系統(tǒng)交互,可以通過Action做遠(yuǎn)程的請求。
- Domain:領(lǐng)域?qū)樱窍到y(tǒng)最為豐富的一層,主要負(fù)責(zé)處理整個系統(tǒng)的業(yè)務(wù)邏輯。這一層包括業(yè)務(wù)服務(wù)和領(lǐng)域?qū)ο螅瑫r負(fù)責(zé)系統(tǒng)的事務(wù)管理。其中業(yè)務(wù)服務(wù)可以提供本地調(diào)用和共享遠(yuǎn)程服務(wù)的功能。
- Persistence:持久化層,主要負(fù)責(zé)數(shù)據(jù)持久化,支持O/R Mapping和JDBC。對數(shù)據(jù)源的訪問提供多種方式。
另外,我們引入了Spring的IOC容器,系統(tǒng)的控制層、領(lǐng)域?qū)雍统志没瘜釉囟加蠭OC容器統(tǒng)一管理,實現(xiàn)完全的接口分離和解耦。同時在控制、領(lǐng)域和持久化層都可以引用日志服務(wù)。
我們對領(lǐng)域驅(qū)動要素的定義上和原有的命名和含義上稍有區(qū)別。
原來的服務(wù)(Service),我們定義為業(yè)務(wù)服務(wù)(BusinessService),面向業(yè)務(wù)服務(wù)的架構(gòu)是GAP平臺的核心設(shè)計思想,一個業(yè)務(wù)服務(wù)可以由一個或多個領(lǐng)域模型和數(shù)據(jù)訪問對象(DAO)組成,去實現(xiàn)一個完整的業(yè)務(wù)邏輯單元。業(yè)務(wù)服務(wù)主要負(fù)責(zé)事務(wù)處理和維護各個領(lǐng)域?qū)ο笾g的關(guān)系,同時為上層訪問提供本地和遠(yuǎn)程服務(wù),服務(wù)類型包括Web Service,RMI等。
領(lǐng)域?qū)ο笥蓪嶓w(Entity)和值對象(VO)構(gòu)成,實體類具備自己的屬性和行為、狀態(tài),可以聚合VO,實體類之間可以有聚合關(guān)聯(lián)等關(guān)系,可以由數(shù)據(jù)訪問對象(DAO)進(jìn)行持久化。
持久化由數(shù)據(jù)訪問對象(DAO)實現(xiàn),不處理業(yè)務(wù)邏輯,主要負(fù)責(zé)實體類的持久化。提供多種持久化方式(O/R Mapping和JDBC)。
那么如何在去實現(xiàn)領(lǐng)域驅(qū)動設(shè)計呢?我們總結(jié)了以下四個步驟:
- 確定業(yè)務(wù)服務(wù)(Business Service):根據(jù)業(yè)務(wù)需求和功能模塊劃分,確定業(yè)務(wù)單元,每個Business Service是一個內(nèi)聚的業(yè)務(wù)單元,覆蓋相關(guān)的領(lǐng)域?qū)ο蟆?/li>
- 定義領(lǐng)域?qū)ο螅‥ntity, VO):根據(jù)業(yè)務(wù)單元的業(yè)務(wù)邏輯定義領(lǐng)域?qū)ο螅ㄟ^UML方法和設(shè)計模式描述領(lǐng)域?qū)ο蟆?/li>
- 定義領(lǐng)域?qū)ο蟮膶傩院完P(guān)聯(lián)關(guān)系:確定領(lǐng)域?qū)ο蟮母鞣N屬性和各個領(lǐng)域?qū)ο笾g的關(guān)聯(lián)關(guān)系。
- 為領(lǐng)域?qū)ο笤黾有袨椋焊鶕?jù)業(yè)務(wù)需求(系統(tǒng)用例和界面原型等)為領(lǐng)域?qū)ο笤黾有袨椋⒍x哪些方法要被業(yè)務(wù)服務(wù)引用。
案例網(wǎng)上書店
為了更好的理解領(lǐng)域驅(qū)動設(shè)計,我們基于以上設(shè)計方法,實現(xiàn)了一套簡單的網(wǎng)上書店系統(tǒng)。
網(wǎng)上書店系統(tǒng)是采用DDD設(shè)計思想構(gòu)建的一個應(yīng)用系統(tǒng)示例。通過網(wǎng)上書店系統(tǒng),可以快速理解領(lǐng)域驅(qū)動設(shè)計。該系統(tǒng)實現(xiàn)網(wǎng)上書店的常用功能:包括瀏覽書籍、挑選書籍、提交訂單、查看訂單、自動折扣、處理訂單、取消訂單等。未登錄用戶可以瀏覽和挑選書籍;已登錄用戶可以提交和查看自己相關(guān)的訂單;管理員可以處理訂單。
經(jīng)過業(yè)務(wù)抽象,即使是這樣一個簡單的業(yè)務(wù)場景也包含了很多領(lǐng)域?qū)ο螅缬唵巍①~戶、書籍、購物車、購物項、折扣等,通過分析和設(shè)計,我們可以得到這樣的設(shè)計圖(為了查看方便,圖中的類隱藏了屬性信息):
BookStoreAction負(fù)責(zé)處理展現(xiàn)層的請求,并把請求轉(zhuǎn)發(fā)給業(yè)務(wù)服務(wù)IBookStoreBS,業(yè)務(wù)服務(wù)負(fù)責(zé)調(diào)度上圖中顯示的領(lǐng)域?qū)ο螅幚碓搱鼍暗乃袠I(yè)務(wù)。
其中領(lǐng)域?qū)ο蠛同F(xiàn)實業(yè)務(wù)的對應(yīng)關(guān)系為:
- Account賬戶
- Order訂單
- Book書籍
- Cart購物車
- Item訂單項
- Discount折扣
與事務(wù)腳本的編程模式不同,領(lǐng)域驅(qū)動設(shè)計不是把業(yè)務(wù)邏輯放在BS(BusinessService)中,而是由具備屬性、行為和狀態(tài)的領(lǐng)域?qū)ο筇幚怼@鏞rder類,如果是貧血的POJO,那它內(nèi)部只有與數(shù)據(jù)表字段對應(yīng)的屬性以及getter和setter方法,而在領(lǐng)域驅(qū)動設(shè)計中,則是一個相對獨立的、能夠處理自身關(guān)聯(lián)業(yè)務(wù)的領(lǐng)域?qū)ο蟆T诒鞠到y(tǒng)中,我們對Order的描述如下:
訂單的實現(xiàn)類是gap.template.bookstore.model.Order,類中除了聯(lián)系方式、郵寄地址等基本屬性外,還有以下領(lǐng)域相關(guān)的行為:
- init(...),結(jié)算時調(diào)用方法,根據(jù)當(dāng)前用戶與購物車中的Items初始化訂單,供用戶修改。
- submit(...),提交訂單時調(diào)用的方法,保存訂單。
- cancel(...),取消訂單,把訂單和相關(guān)item的狀態(tài)設(shè)置為已取消,然后委托Dao進(jìn)行持久化。
- dispose(...),處理訂單,首先更新訂單項的狀態(tài),然后委托Dao持久化訂單數(shù)據(jù)。
- reSubmit、setItemsStatus......
通過以上的描述,我們可以看到,Order類基本上覆蓋了現(xiàn)實世界中訂單這個業(yè)務(wù)的所有行為和狀態(tài),是相對內(nèi)聚的,這樣的特性使其復(fù)用性大大增加,即使未來開發(fā)新的模塊,涉及到訂單業(yè)務(wù)的,可以直接復(fù)用Order類。同時在后期維護中,如果我想了解訂單的業(yè)務(wù),直接讀Order的代碼就可以了。
從上圖中我們還可以清晰的看到各個領(lǐng)域?qū)ο笾g的關(guān)系。Order和Cart都聚合了Item,對應(yīng)都是1...n,Item聚合了Book,對應(yīng)關(guān)系1...1。Order分別與折扣、賬戶發(fā)生關(guān)聯(lián)和調(diào)用等等,整個網(wǎng)上書店的場景就這樣描述出來了。
另外,不要忘了BS,除了起到基礎(chǔ)設(shè)施的作用外(事務(wù)管理和服務(wù)共享),它還要負(fù)責(zé)調(diào)度和維護領(lǐng)域?qū)ο笾g的關(guān)系。因為總會有些業(yè)務(wù)邏輯,既不屬于這個領(lǐng)域?qū)ο螅膊粚儆谀莻€,那這部分業(yè)務(wù)由誰來處理呢?由BS來處理。例如在管理員處理訂單這個場景中,首先需要根據(jù)訂單信息獲取賬戶,根據(jù)賬戶信息確定折扣率,同時進(jìn)行余額校驗,如果校驗通過,就會調(diào)用訂單對象的dispose方法處理訂單,這個場景會涉及到Order、Account、Discount等對象,這樣的業(yè)務(wù)邏輯,應(yīng)該由BS實現(xiàn)。
IBookStoreDao是數(shù)據(jù)訪問對象,可以被BS調(diào)用,用來持久化對象,也可以被領(lǐng)域?qū)ο笠茫脕沓志没陨怼?/p>
通過以上的描述,我們可以看到,整個設(shè)計和實現(xiàn)是優(yōu)雅、清晰的。業(yè)務(wù)邏輯沒有堆積在BS中,而是分散在BS和各個領(lǐng)域?qū)ο笾校?wù)和對象都與現(xiàn)實世界的業(yè)務(wù)息息相關(guān),無論是對領(lǐng)域?qū)<摇㈤_發(fā)人員和后期維護人員,都能這種方式中獲得自己需要的內(nèi)容。
總結(jié)
我們采用領(lǐng)域驅(qū)動設(shè)計相對比較早,就我個人的檢驗和實踐而言,DDD對構(gòu)建企業(yè)級應(yīng)用開發(fā)平臺和大型核心業(yè)務(wù)系統(tǒng)的作用是非常明顯的,無論是在產(chǎn)品的穩(wěn)定性、擴展性、可維護性、生命周期等方面都有顯著的提升。
但是,由于這樣那樣的原因(復(fù)雜度、工期、開發(fā)人員能力限制等等),很多人會不自覺的抵制采用DDD,有時候一個軟件項目重寫了兩次,第二次依然不去做良好的設(shè)計。事實上采用了DDD的設(shè)計方法,我們的設(shè)計階段已經(jīng)變得非常輕量級和敏捷了,開發(fā)人員只要能夠把領(lǐng)域模型之間的關(guān)系畫出來并描述說明,并與需求人員達(dá)成一致,那么做出來的東西基本上是靠譜的。
在技術(shù)領(lǐng)域,只有主動的嘗試和提升,效果才是最明顯的。很多人問過我,如何開始學(xué)習(xí)和實踐XXX,其實很簡單,現(xiàn)在就開始吧!
it知識庫:領(lǐng)域驅(qū)動設(shè)計和實踐,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。