• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看

      ?

      游戲引擎中事件和響應(yīng)機(jī)制的研究

      2022-05-30 12:16:27江紅偉米洪
      電腦知識(shí)與技術(shù) 2022年22期
      關(guān)鍵詞:事件委托

      江紅偉 米洪

      摘要:文章建立在抽象思維的基礎(chǔ)上,對(duì)觀察者模式進(jìn)行了系統(tǒng)研究,并將這種良好的思維模式應(yīng)用于實(shí)際的游戲引擎開發(fā)實(shí)例中。闡述了基于觀察者模式的委托、事件、消息傳遞與響應(yīng)的關(guān)系,實(shí)現(xiàn)程序中各類對(duì)象之間協(xié)同工作,弱化具體類之間的耦合關(guān)系,使得某些相互有聯(lián)系的對(duì)象間不需要依賴對(duì)方而實(shí)現(xiàn)必要的通信與交互。最后在Unity3D中通過具體實(shí)例講述了回調(diào)系統(tǒng)內(nèi)置事件方法,以及.net泛型委托方法之間的差異,并通過事件傳遞消息的方法給出了游戲引擎開發(fā)中對(duì)象間完全解耦的解決方案。

      關(guān)鍵詞:觀察者模式;委托;事件;消息傳遞

      中圖分類號(hào):TP311.1? ? ? 文獻(xiàn)標(biāo)識(shí)碼:A

      文章編號(hào):1009-3044(2022)22-0083-04

      1 引言

      Unity3D是現(xiàn)在主流的3D游戲引擎,它支持多種面向?qū)ο蟮恼Z言,其中C#語言的應(yīng)用最為廣泛,是典型的游戲開發(fā)和虛擬現(xiàn)實(shí)開發(fā)的代表。在一個(gè)游戲系統(tǒng)的設(shè)計(jì)中,事件和響應(yīng)機(jī)制的應(yīng)用是不可回避的技術(shù)。在開發(fā)中,什么時(shí)候回調(diào)引擎基類MonoBehavior的事件、什么時(shí)候使用.net平臺(tái)的事件系統(tǒng),是編程邏輯時(shí)刻需要解決的問題。

      本文重點(diǎn)探討和研究C#語言中基于觀察者模式的事件和響應(yīng)機(jī)制。一方面要盡量實(shí)現(xiàn)類的單一性原則,即一個(gè)類應(yīng)該專注于做一件事情;另一方面,應(yīng)該把程序中不變的部分分離出來形成抽象層、變動(dòng)的部分形成各個(gè)不關(guān)聯(lián)的具體執(zhí)行層、減少耦合度,以達(dá)到程序中對(duì)象間的“低耦合、高內(nèi)聚”的目標(biāo)。

      2 接口和抽象類

      在面向?qū)ο蟮母拍钪?,所有的?duì)象都是通過類來描繪的,但是反過來并不是所有的類都是用來描繪對(duì)象的。如果一個(gè)類中沒有包含具體的實(shí)現(xiàn),這樣的類就是抽象類。抽象類基本是用來表征在對(duì)問題領(lǐng)域進(jìn)行分析、設(shè)計(jì)中得出的抽象概念,是對(duì)一系列看上去不同,但是本質(zhì)上相同的具體概念的抽象[1]。一般來說,可以構(gòu)造出一個(gè)固定的具有一組行為的抽象描述,但是這組行為卻能夠擁有任意多個(gè)可能的具體實(shí)現(xiàn)。這個(gè)抽象的描述就是抽象類,而這一組任意多個(gè)可能的具體實(shí)現(xiàn)則表現(xiàn)為所有可能的派生類。接口可以被看作是抽象類的變體,接口中所有的方法都是抽象的,可以通過接口來間接地實(shí)現(xiàn)多重繼承。

      接口和抽象類是面向?qū)ο缶幊痰幕?,賦予了C#語言強(qiáng)大的面向?qū)ο蟮哪芰?,為類的封裝、繼承和多態(tài)提供良好的設(shè)計(jì)基礎(chǔ)。在程序設(shè)計(jì)中,各類對(duì)象協(xié)同工作,對(duì)象之間通過封裝和繼承等方式進(jìn)行通信,良好的協(xié)同工作是需要以接口和抽象類為基礎(chǔ)而展開的。

      根據(jù)里氏代換原則,派生類可以實(shí)現(xiàn)基類的抽象方法,而且基類應(yīng)該不需要知道派生類的具體行為。接口和抽象類都屬于基類,是對(duì)業(yè)務(wù)邏輯的抽象,將派生類的方法進(jìn)行了一定的規(guī)范,具體的實(shí)現(xiàn)是由派生類來完成的。當(dāng)需求有變化時(shí),只需建立新的子類來實(shí)現(xiàn)接口或抽象類就可以擴(kuò)展出新的功能,而原有的依賴于該基類的派生類則不需要修改,做到了程序間的“低耦合”性,甚至“無耦合”性。這樣即可實(shí)現(xiàn)“開閉原則”,使得程序具有較好的擴(kuò)展性的同時(shí),又可以實(shí)現(xiàn)對(duì)子類修改的關(guān)閉,從而避免了程序員各自寫的子類之間的相互影響,減少子類修改對(duì)于整個(gè)系統(tǒng)帶來的影響。

      總之,接口和抽象類都是對(duì)客戶端程序的一種承諾,應(yīng)該做到相對(duì)不變[2]。同時(shí)根據(jù)接口隔離原則,接口應(yīng)當(dāng)為客戶提供盡可能小的規(guī)范[3],以明確地區(qū)分各個(gè)接口和抽象類的分工和特征。

      3 觀察者模式

      在一個(gè)軟件系統(tǒng)中,各類對(duì)象之間是協(xié)同工作的,對(duì)象之間可以通過繼承、實(shí)例等進(jìn)行消息傳遞。假如一個(gè)對(duì)象的行為發(fā)生變化時(shí),和這個(gè)對(duì)象有關(guān)聯(lián)的其他對(duì)象都需要在程序結(jié)構(gòu)上進(jìn)行重寫,則這種情況就導(dǎo)致了對(duì)象之間的完全依賴、形成緊密的耦合。所以好的設(shè)計(jì)模式需要借以優(yōu)秀的,可以方便開發(fā)者復(fù)用的程序設(shè)計(jì)模式[4]來構(gòu)建良好的程序關(guān)系。

      “觀察者模式(Observer mode) ”或稱“發(fā)布-訂閱模式(Publish/Subscribe) ”屬于設(shè)計(jì)模式中的行為模型,可以弱化具體類之間的耦合關(guān)系,使得某些相互有聯(lián)系的對(duì)象間不需要依賴對(duì)方而實(shí)現(xiàn)必要的通信與交互。該模式定義了對(duì)象間的一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽某一個(gè)主題對(duì)象[5]。這個(gè)目標(biāo)對(duì)象在狀態(tài)發(fā)生變化時(shí),會(huì)通知所有的觀察者對(duì)象,使它們能夠自動(dòng)更新[6]。且主題發(fā)出通知并不需要知道具體的觀察者對(duì)象,觀察者之間也不需要知道其他觀察者的存在。觀察者模式在降低程序間耦合度的同時(shí)能夠維持好對(duì)象間行動(dòng)的一致性,保證程序間的高度協(xié)作性。

      如圖1所示:Subject類(目標(biāo)類,是廣播者) 一般被定義為抽象類,其中保存了Observer類(觀察者類,是訂閱者) 的集合,所以可以讓多個(gè)觀察者同時(shí)監(jiān)聽該目標(biāo)。此外它提供給ConcreteSubject類(具體目標(biāo)類) 需要實(shí)現(xiàn)的抽象方法,以規(guī)范目標(biāo)類中具體方法的實(shí)現(xiàn)。

      Observer類(觀察者類) 一般定義為接口,可以使得多個(gè)ConcreteObserver類(具體觀察者類) 繼承于該接口。這樣使得各個(gè)具體觀察者對(duì)象可以被保存在Subject類的Observer集合中,使得具體目標(biāo)類可以遍歷到各個(gè)具體觀察者對(duì)象,并對(duì)其發(fā)送通知,實(shí)現(xiàn)多播效果。最后具體觀察者接收到通知并執(zhí)行各自的實(shí)現(xiàn)方法。

      觀察者模式實(shí)現(xiàn)了目標(biāo)類與觀察者類之間的抽象耦合,目標(biāo)類只需要保存觀察者對(duì)象的引用,并不需要知道具體觀察者是誰,具體觀察者只需遵守接口的約定即可。通過傳統(tǒng)的抽象類和接口的方式可以實(shí)現(xiàn)該模式,也可以通過.net框架中的委托(Delegates) 與事件(Event) 機(jī)制來實(shí)現(xiàn),相對(duì)來說委托和事件機(jī)制能進(jìn)一步弱化目標(biāo)類和觀察者類之間的依賴關(guān)系[7]。

      4 委托與事件

      所有的委托類型都派生于基類System.Delegate。使用委托的時(shí)候,廣播者類包含一個(gè)委托字段,廣播者通過調(diào)用委托來決定什么時(shí)候進(jìn)行廣播;觀察者類(訂閱者類) 是方法目標(biāo)的接收者,通過在委托上調(diào)用“+=”開始進(jìn)行監(jiān)聽、調(diào)用“-=”結(jié)束監(jiān)聽[7];一個(gè)訂閱者不需要知道也不會(huì)干擾其他的訂閱者,以實(shí)現(xiàn)訂閱者之間的解耦。

      實(shí)際上,委托是不可變的,使用“+=”或“-=”操作符時(shí),其實(shí)是創(chuàng)建了新的委托實(shí)例,并把它賦值給了當(dāng)前的委托變量,初始狀態(tài)時(shí)這個(gè)委托變量可以是null,如圖2所示。

      在實(shí)際的使用中,泛型委托可以提供了更好的便捷性,下面的程序中定義了一個(gè)返回類型和傳參類型都為Object的泛型委托,并且創(chuàng)建了一個(gè)發(fā)布者類,聲明了這個(gè)泛型委托的實(shí)例對(duì)象OnPublisher,利用發(fā)布方法。

      Publish調(diào)用了該對(duì)象委托的方法,并使用一個(gè)公有字段“output”接收了該委托的返回值,如圖3所示。

      委托的方法便是觀察者類的具體實(shí)現(xiàn)方法,當(dāng)然可以同時(shí)委托多個(gè)觀察者以不同的實(shí)現(xiàn)方法,只需這些方法的簽名和委托類的約定一致就行[8],這里示例了一個(gè)觀察者類的實(shí)現(xiàn)方法,用來傳入一個(gè)整數(shù)并返回一個(gè)整型數(shù)值,如圖4所示。

      最后在客戶端程序中將觀察者的實(shí)現(xiàn)方法賦值給委托對(duì)象,調(diào)用委托的發(fā)布方法并進(jìn)行傳值。這樣幾個(gè)程序間相互獨(dú)立、各司其職,發(fā)布者和觀察者之間解耦了,如圖5所示。

      .net3.5以后還提供了兩類通用的delegates,如果方法有返回值,則使用Func或者Func<>;如果方法沒有返回值,則使用Action或者Action<>。所以上例中的泛型委托就可以直接由Func<>創(chuàng)建委托對(duì)象了,而不用首先定義委托。<>中左側(cè)是傳參類型、右側(cè)是返回值類型,最多可以有16個(gè)傳參,如圖6所示。

      本例打印輸出結(jié)果為“9”。如果使用不帶返回值的泛型委托得到同樣的輸出結(jié)果,則可以使用Action<>型委托,<>中定義的是傳值類型,最多也可以有16個(gè)。重構(gòu)這三個(gè)類,如圖7、圖8、圖9所示。

      事件(event) 是對(duì)委托進(jìn)一步封裝的結(jié)果,讓委托只暴露特定的部分子集,防止訂閱者之間相互干擾,可以安全地實(shí)現(xiàn)廣播者/訂閱者模式[8]。在Subject類外,只能通過“+=”和“-=”來注冊(cè)和注銷事件、即事件訪問器只能通過“+=” 和“-=”來實(shí)現(xiàn)。只需引入“event”關(guān)鍵字就可以將委托封裝為事件。如上例,將“public static Action OnPublisher”改為“public static event Action OnPublisher”,即可。

      5 Unity3D的事件和響應(yīng)

      在Unity3D中為了響應(yīng)一個(gè)GameObject的事件分發(fā),常規(guī)的做法是回調(diào)系統(tǒng)相關(guān)的內(nèi)置事件。而MonoBehaviour是Unity中所有腳本的基類,使用C#需要顯式的從MonoBehaviour繼承系統(tǒng)內(nèi)置的事件[9]。

      為了講述事件與響應(yīng)的關(guān)系,在場(chǎng)景制作了3個(gè)三維物體作為按鈕對(duì)象,并給它們配置好Collider碰撞組件。設(shè)計(jì)目標(biāo)是讓鼠標(biāo)和這3個(gè)按鈕對(duì)象之間產(chǎn)生互動(dòng)效果,如圖10所示。

      建立一個(gè)類繼承自MonoBehaviour基類,分別回調(diào)鼠標(biāo)滑過事件(OnMouseOver) 、鼠標(biāo)退出事件(OnMouseExit) 。

      Unity3D中繼承自MonoBehaviour的類形成實(shí)例的方法是將它作為組件掛載給游戲?qū)ο骩9],所以這3個(gè)按鈕對(duì)象必須分別掛載這個(gè)繼承類。

      這種做法雖然很輕松就實(shí)現(xiàn)了這3個(gè)三維按鈕的鼠標(biāo)交互效果,但是這種程序結(jié)構(gòu)很不友好。誰是廣播者、誰是訂閱者似乎無法分辨。程序所有的功能都被寫在了這一個(gè)類里,全耦合且毫無內(nèi)聚性可言,這樣導(dǎo)致項(xiàng)目幾乎沒有擴(kuò)展與維護(hù)的可能性,牽一發(fā)則動(dòng)全身。而且程序是被掛載到場(chǎng)景中的每個(gè)游戲?qū)ο笊系?,后期想要修改游戲?qū)ο蟮男袨?,則要人工地逐個(gè)去檢查、修改每一個(gè)對(duì)象的各個(gè)實(shí)現(xiàn)方法。當(dāng)場(chǎng)景變大后,這個(gè)修改工作將是龐大而煩瑣的過程。這個(gè)回調(diào)系統(tǒng)事件類的基本樣式如圖11所示。

      上文中已經(jīng)探討了“發(fā)布-訂閱”模式的優(yōu)勢(shì),再借助.net事件機(jī)制,完全可以設(shè)計(jì)出較為優(yōu)秀的程序結(jié)構(gòu)?;驹硎牵簩懸粋€(gè)發(fā)布者類,利用場(chǎng)景中的主攝像機(jī)發(fā)出射線與場(chǎng)景中的Collider組件對(duì)象發(fā)生碰撞,這種碰撞有三種狀態(tài),分別是射線進(jìn)入某對(duì)象、停留在某對(duì)象上和離開某對(duì)象;程序設(shè)計(jì)上可以把這個(gè)三個(gè)狀態(tài)分別定義為三個(gè)事件OnRayEnter、OnRayStay、OnRayExit,而這些事件只需要傳遞參數(shù)、不需要有返回值,所以可以使用Action<>型的委托事件來實(shí)現(xiàn);傳遞的參數(shù)就是由不同的事件而捕捉到的射線碰撞對(duì)象,然后由一個(gè)觀察者類來接收這些事件所傳遞出來的參數(shù),根據(jù)傳遞過來的不同的Collider組件對(duì)象來做一些具體的事務(wù)。

      因?yàn)榘l(fā)布者類和觀察者類都不需要回調(diào)Unity3D系統(tǒng)的內(nèi)置事件,所以它們是無須繼承系統(tǒng)基類的,這樣也就無需將這兩個(gè)類掛載給場(chǎng)景對(duì)象來形成實(shí)例。只需在客戶端程序?qū)@兩個(gè)類實(shí)例化后,直接將對(duì)應(yīng)的觀察者方法注冊(cè)給發(fā)布者的對(duì)應(yīng)事件,就建立了發(fā)布者事件和觀察者實(shí)現(xiàn)方法之間的聯(lián)系。發(fā)布者類和觀察者類的基本樣式如圖12、圖13所示。

      而客戶端程序仍然需要繼承MonoBehaviour基類,因?yàn)樗仨毣卣{(diào)Unity3D系統(tǒng)的Start()和Update()函數(shù)。在Start()函數(shù)中對(duì)事件進(jìn)行注冊(cè),在Update()函數(shù)中回調(diào)發(fā)布者類的射線碰撞方法,并進(jìn)行事件發(fā)布??蛻舳祟惖幕緲邮饺鐖D14所示。

      最后將這個(gè)客戶端類掛載給場(chǎng)景中的一個(gè)空物體上,讓它形成一個(gè)實(shí)例。前例中,程序都被分散地掛載在各個(gè)游戲?qū)ο笊?,?dǎo)致管理上非常混亂。而這里,場(chǎng)景中的資源被這個(gè)“空物體”統(tǒng)一化處理了,規(guī)范化了場(chǎng)景資源的管理。

      利用.net事件機(jī)制,發(fā)布者和觀察者之間一定程度上實(shí)現(xiàn)了解耦,發(fā)布者和觀察者各自只做自己該做的事、實(shí)現(xiàn)了高內(nèi)聚,也大大方便了項(xiàng)目后期的增、刪、改、查。

      6 Unity3D中為事件傳遞消息

      上文已經(jīng)實(shí)現(xiàn)了發(fā)布者模式的程序結(jié)構(gòu),但是還需要繼續(xù)完善一下,因?yàn)榘l(fā)布者還是需要傳參給觀察者的,導(dǎo)致這兩個(gè)類之間沒有完全解耦。這時(shí),可以考慮事件的消息傳遞機(jī)制,以達(dá)到完全解耦的目標(biāo)。

      .net平臺(tái)中定義了一個(gè)基類EventArgs專門用來為事件傳遞消息。還定義了一個(gè)泛型委托EventHandler,可傳遞兩個(gè)參數(shù),第一個(gè)類型是Object類,是發(fā)布者;第二類型便是EventArgs類,是消息傳遞類[8]。

      所以,可以建立一個(gè)繼承EventArgs的類,專門用作事件的消息傳遞,作為發(fā)布者類和觀察者類之間信息傳遞的橋梁。這樣觀察者就不必知道發(fā)布者所傳遞的是什么了,便可實(shí)現(xiàn)發(fā)布者和觀察者之間的完全解耦。

      首先創(chuàng)建一個(gè)繼承EventArgs基類的消息傳遞類PublisherEventArgs,其中定義兩個(gè)公開的屬性,分別是上一幀的碰撞信息、當(dāng)前幀的碰撞信息。并通過構(gòu)造函數(shù)對(duì)相應(yīng)屬性進(jìn)行賦值,如圖15所示。

      發(fā)布者類中,重新定義三個(gè)事件為EventHandler型委托事件,并創(chuàng)建消息傳遞類PublisherEventArg的變量e,如圖16所示。

      對(duì)于事件的發(fā)布方法CollisionProcess(),首先對(duì)變量e進(jìn)行實(shí)例化“e = new PublisherEventArgs(colliderOld, current)”;事件發(fā)布器的參數(shù)改為泛型委托EventHandler所規(guī)定的兩類型參數(shù)“OnRayExit?.Invoke(this, e)”、“OnRayStay?.Invoke(this, e)”、“OnRayExit?.Invoke(this, e)”。這樣就可以讓相應(yīng)事件發(fā)生時(shí)的碰撞對(duì)象參數(shù)傳遞給PublisherEventArgs類的構(gòu)造函數(shù)。

      游戲運(yùn)行過程中,每幀都會(huì)傳兩個(gè)參數(shù)過去,第一個(gè)參數(shù)是上一幀的碰撞信息、第二個(gè)是當(dāng)前幀的碰撞信息。這樣就無需像上例那樣,針對(duì)不同的事件發(fā)布器還要人為判斷所傳參數(shù)到底是上一幀的碰撞對(duì)象還是當(dāng)前幀的,避免了人工判斷可能導(dǎo)致的失誤。

      此時(shí),觀察者就完全與發(fā)布者無關(guān)了,只與消息傳遞類PublisherEventArgs有關(guān)系,其實(shí)現(xiàn)方法RayInputIn()和RayInputOut()寫法大致如圖17所示。

      最后客戶端程序也變得簡(jiǎn)單了,只需對(duì)事件進(jìn)行注冊(cè),無須考慮事件要傳什么參數(shù)給委托方法。因?yàn)槭录揪蜎]有傳參給所委托的方法,而是直接傳給了消息傳遞類,這時(shí)發(fā)布者和觀察者之間就完全解耦了。事件注冊(cè)寫法如“publisherSubject.OnRayEnter += observerObject.RayInputIn”,其他兩個(gè)事件的注冊(cè)和此寫法類同。

      7 結(jié)束語

      游戲引擎的事件和響應(yīng)的機(jī)制,歸根究底還是要從面向?qū)ο蟮母境霭l(fā),帶著抽象思維去思考問題;從軟件設(shè)計(jì)模式出發(fā),借助優(yōu)秀的、可以方便開發(fā)者復(fù)用的程序設(shè)計(jì)模式來構(gòu)建良好的程序關(guān)系。

      基于觀察者模式的程序設(shè)計(jì)思維,利用好委托、事件和消息傳遞機(jī)制,這些對(duì)于實(shí)現(xiàn)觀察者模式有的獨(dú)到的支撐和便利的工具,來設(shè)計(jì)和優(yōu)化Unity3D的程序模塊,可以很好地做到對(duì)象間“低耦合”甚至“無耦合”的目標(biāo)。

      參考文獻(xiàn):

      [1] 曹步清,金甌.Java中的Abstract Class與Interface技術(shù)研究[J].計(jì)算機(jī)技術(shù)與發(fā)展,2006,16(8):110-112,115.

      [2] 耿祥義,張躍平.Java設(shè)計(jì)模式[M].北京:清華大學(xué)出版社,2009:132-134.

      [3] 李航.基于MDA的BSS計(jì)費(fèi)系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[D].哈爾濱:哈爾濱工業(yè)大學(xué),2012:24.

      [4] Gamma E,Helm R,Johns R,et al.Design patterns: elements of reusable object-oriented software[M].Beijing:China Machine Press,2002.

      [5] 孟婷婷,何利力.Observer設(shè)計(jì)模式在手機(jī)導(dǎo)航軟件中的應(yīng)用[J].電腦知識(shí)與技術(shù),2014,10(19):4579-4582.

      [6] Gamma E,Helm R,Johns R.設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)[M].李英軍,馬曉星,蔡敏,等譯.北京:機(jī)械工業(yè)出版社,2005:89.

      [7] 吳清壽.基于事件機(jī)制的觀察者模式及應(yīng)用[J].重慶理工大學(xué)學(xué)報(bào)(自然科學(xué)版),2012,26(9):100-104.

      [8] 微軟公司.基于C#的.NET Framework程序設(shè)計(jì)[M].北京:高等教育出版社,2004:149-152.

      [9] 楊秀杰,楊麗芳.虛擬現(xiàn)實(shí)(VR)交互程序設(shè)計(jì)[M].北京:中國水利水電出版社,2019:34-38.

      【通聯(lián)編輯:謝媛媛】

      猜你喜歡
      事件委托
      建設(shè)項(xiàng)目合同事項(xiàng)受托回避與合并委托問題探討
      Contiki系統(tǒng)進(jìn)程與事件剖析
      網(wǎng)絡(luò)輿情反轉(zhuǎn)現(xiàn)象中的“參照點(diǎn)效應(yīng)”
      新聞界(2016年7期)2016-12-23 14:56:11
      保羅·利科的“話語事件”思想
      授之以魚,不如授之以漁
      考試周刊(2016年92期)2016-12-08 00:10:56
      熱點(diǎn)事件中的“輿論搭車”現(xiàn)象探析
      新聞前哨(2016年11期)2016-12-07 11:25:41
      績效評(píng)價(jià)在委托管理酒店中的應(yīng)用
      新聞前哨(2016年1期)2016-12-01 06:18:04
      嵌入式系統(tǒng)課程“中斷、異常與事件”教學(xué)實(shí)踐及啟示
      治理現(xiàn)代化:委托制下的權(quán)力清單制
      招標(biāo)代理中的授權(quán)委托——以案說法
      桂阳县| 海晏县| 崇礼县| 高尔夫| 山东省| 临颍县| 定日县| 沅陵县| 边坝县| 通山县| 保靖县| 兰考县| 阳西县| 临桂县| 黑龙江省| 潜山县| 嵊泗县| 葫芦岛市| 长海县| 高阳县| 肃宁县| 莎车县| 庄浪县| 新津县| 自治县| 阿克| 晴隆县| 南溪县| 中江县| 格尔木市| 赤水市| 白玉县| 丰都县| 苗栗县| 紫金县| 巴塘县| 蒙阴县| 银川市| 肥西县| 收藏| 炎陵县|