• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            loop_in_codes

            低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

            低耦合模塊間的通信組件:兩個(gè)模板

            用途

            在一個(gè)UI與邏輯模塊交互比較多的程序中,因?yàn)椴⒉幌胱寖蓚€(gè)模塊發(fā)生太大的耦合,基本目標(biāo)是
            可以完全不改代碼地?fù)Q一個(gè)UI。邏輯模塊需要在產(chǎn)生一些事件后通知到UI模塊,并且在這個(gè)通知
            里攜帶足夠多的信息(數(shù)據(jù))給接收通知的模塊,例如UI模塊。邏輯模塊還可能被放置于與UI模
            塊不同的線程里。

            最初的結(jié)構(gòu)

            最開(kāi)始我直接采用最簡(jiǎn)單的方法,邏輯模塊保存一個(gè)UI模塊傳過(guò)來(lái)的listener。當(dāng)有事件發(fā)生時(shí),
            就回調(diào)相應(yīng)的接口將此通知傳出去。大致結(jié)構(gòu)如下:

             /// Logic
             class EventNotify
             
            {
             
            public:
              
            virtual void OnEnterRgn( Player *player, long rgn_id );
             }
            ;

             
            /// UI
             class EventNotifyImpl : public EventNotify
             
            {
             }
            ;

             
            /// Logic
             GetEventNotify()->OnEnterRgn( player, rgn_id );

             

            但是,在代碼越寫(xiě)越多之后,邏輯模塊需要通知的事件越來(lái)越多之后,EventNotify這個(gè)類(lèi)開(kāi)始
            膨脹:接口變多了、不同接口定義的參數(shù)看起來(lái)也越來(lái)越惡心了。

            改進(jìn)

            于是我決定將各種事件通知統(tǒng)一化:

             

            struct Event
            {
             
            long type; // 事件類(lèi)型
              // 附屬參數(shù)
            }
            ;

             

            這樣,邏輯模塊只需要?jiǎng)?chuàng)建事件結(jié)構(gòu),兩個(gè)模塊間的通信就只需要一個(gè)接口即可:

            void OnNotify( const Event &event );

            但是問(wèn)題又來(lái)了,不同的事件類(lèi)型攜帶的附屬參數(shù)(數(shù)據(jù))不一樣。也許,可以使用一個(gè)序列化
            的組件,將各種數(shù)據(jù)先序列化,然后在事件處理模塊對(duì)應(yīng)地取數(shù)據(jù)出來(lái)。這樣做總感覺(jué)有點(diǎn)大動(dòng)
            干戈了。當(dāng)然,也可以使用C語(yǔ)言里的不定參數(shù)去解決,如:

            void OnNotify( long event_type, ... )

            其實(shí),我需要的就是一個(gè)可以表面上類(lèi)型一樣,但其內(nèi)部保存的數(shù)據(jù)卻多樣的東西。這樣一想,
            模塊就能讓事情簡(jiǎn)單化:

             

            template <typename P1, typename P2>
            class Param
            {
            public:
             Param( P1 p1, P2 p2 ) : _p1( p1 ), _p2( p2 )
             
            {
             }

             
             P1 _p1;
             P2 _p2;
            }
            ;

            template 
            <typename P1, typename P2>
            void OnNotify( long event_type, Param<P1, P2> param );

            GetNotify()
            ->OnNotify( ET_ENTER_RGN, Param<Player*long>( player, rgn_id ) );
            GetNotify()
            ->OnNotify( ET_MOVE, Param<longlong>( x, y ) );

             

            在上面這個(gè)例子中,雖然通過(guò)Param的包裝,邏輯模塊可以在事件通知里放置任意類(lèi)型的數(shù)據(jù),但
            畢竟只支持2個(gè)參數(shù)。實(shí)際上為了實(shí)現(xiàn)支持多個(gè)參數(shù)(起碼得有15個(gè)),還是免不了自己實(shí)現(xiàn)多個(gè)
            參數(shù)的Param。

            幸虧我以前寫(xiě)過(guò)宏遞歸產(chǎn)生代碼的東西,可以自動(dòng)地生成這種情況下諸如Param1、Param2的代碼。
            如:

             

            #define CREATE_PARAM( n ) \
             template 
            <DEF_PARAM( n )> \
             
            struct Param##n \
             
            { \
              DEF_PARAM_TYPE( n ); \
              Param##n( DEF_FUNC_PARAM( n ) ) \
              
            { \
               DEF_MEM_VAR_ASSIGN( n ); \
              }
             \
              DEF_VAR_DEF( n ); \
             }


             CREATE_PARAM( 
            1 );
             CREATE_PARAM( 
            2 );

             

            即可生成Param1和Param2的版本。其實(shí)這樣定義了Param1、Param2的東西之后,又使得OnNotify
            的參數(shù)不是特定的了。雖然可以把Param也泛化,但是在邏輯層寫(xiě)過(guò)多的模板代碼,總感覺(jué)不好。

            于是又想到以前寫(xiě)的一個(gè)東西,可以把各種類(lèi)型包裝成一種類(lèi)型---對(duì)于外界而言:any。any在
            boost中有提到,我只是實(shí)現(xiàn)了個(gè)簡(jiǎn)單的版本。any的大致實(shí)現(xiàn)手法就是在內(nèi)部通過(guò)多態(tài)機(jī)制將各
            種類(lèi)型在某種程度上隱藏,如:

             

                    class base_type
                    
            {
                    
            public:
                        
            virtual ~base_type()
                        
            {
                        }

                        
            virtual base_type *clone() const = 0;
                    }
            ;
                    
                    template 
            <typename _Tp>
                    
            class var_holder : public base_type
                    
            {
                    
            public:
                        typedef _Tp type;
                        typedef var_holder
            <type> self;
                    
            public:
                        var_holder( 
            const type &t ) : _t( t )
                        
            {
                        }


                        base_type 
            *clone() const
                        
            {
                            
            return new self( _t );
                        }

                    
            public:
                        type _t;
                    }


            這樣,any類(lèi)通過(guò)一個(gè)base_type類(lèi),利用C++多態(tài)機(jī)制即可將類(lèi)型隱藏于var_holder里。那么,
            最終的事件通知接口成為下面的樣子:

            void OnNotify( long type, any data );

            OnNotify( ET_ENTER_RGN, any( create_param( player, rgn_id ) ) );其中,create_param
            是一個(gè)輔助函數(shù),用于創(chuàng)建各種Param對(duì)象。

            事實(shí)上,實(shí)現(xiàn)各種ParamN版本,讓其名字不一樣其實(shí)有點(diǎn)不妥。還有一種方法可以讓Param的名字
            只有一個(gè),那就是模板偏特化。例如:

             

            template <typename _Tp>
            struct Param;

            template 
            <>
            struct Param<void()>;

            template 
            <typename P1>
            struct Param<void(P1)>

            template 
            <typename P1, typename P2>
            struct Param<void(P1,P2)>

             

            這種方法主要是通過(guò)組合出一種函數(shù)類(lèi)型,來(lái)實(shí)現(xiàn)偏特化。因?yàn)槲矣X(jué)得構(gòu)造一個(gè)函數(shù)類(lèi)型給主模版,
            并不是一種合情理的事情。但是,即使使用偏特化來(lái)讓Param名字看起來(lái)只有一個(gè),但對(duì)于不同的
            實(shí)例化版本,還是不同的類(lèi)型,所以還是需要any來(lái)包裝。

            實(shí)際使用

            實(shí)際使用起來(lái)讓我覺(jué)得非常賞心悅目。上面做的這些事情,實(shí)際上是做了一個(gè)不同模塊間零耦合
            通信的通道(零耦合似乎有點(diǎn)過(guò)激)?,F(xiàn)在邏輯模塊通知UI模塊,只需要定義新的事件類(lèi)型,在
            兩邊分別寫(xiě)通知和處理通知的代碼即可。

            PS:
            針對(duì)一些評(píng)論,我再解釋下。其實(shí)any只是用于包裝Param列表而已,這里也可以用void*,再轉(zhuǎn)成
            Param*。在這里過(guò)多地關(guān)注是用any*還是用void*其實(shí)偏離了本文的重點(diǎn)。本文的重點(diǎn)其實(shí)是Param:

             

            OnNotify( NT_ENTER_RGN, ang( create_param( player, rgn_id ) ) );

            ->
            void OnNotify( long type, any data )
            {
             Param2
            <Player*long> ParamType;
             ParamType 
            *= any_cast<ParamType>&data );
             Player 
            *player = p->p1;
             
            long rgn_id = p->p2;
            }




            下載相關(guān)代碼

            posted on 2009-08-23 09:55 Kevin Lynx 閱讀(6369) 評(píng)論(18)  編輯 收藏 引用 所屬分類(lèi): 模塊架構(gòu)

            評(píng)論

            # re: 低耦合模塊間的通信組件:兩個(gè)模板[未登錄](méi) 2009-08-23 10:19 Davy.xu

            很好的設(shè)計(jì),收下了  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板[未登錄](méi) 2009-08-23 10:58 megax

            唉,我還是用void*吧  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 13:27 OwnWaterloo

            @megax
            同意。 一旦any_cast出錯(cuò),就是一個(gè)不能逃避,必須得修改掉的錯(cuò)誤。
            相對(duì)于void*, any能起到的作用只是開(kāi)發(fā)時(shí)的debug?
            發(fā)布時(shí)再改回?zé)o檢查的void* ? 還要注意釋放的問(wèn)題……
              回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 13:35 OwnWaterloo

            嘿嘿嘿嘿~~~
            設(shè)計(jì)來(lái)、設(shè)計(jì)去,回到了經(jīng)典的WndProc模式:
            typedef HRESULT (CALLBACK* WndProc)(HWND,UINT,WPARAM,LPARAM);


            因?yàn)楝F(xiàn)在有模板這個(gè)高級(jí)貨, 所以HWND,WPARAM,LPARAM可以塞到一起,變成:
            typedef R (*OnNotify)(long type, xxx data);


            然后呢, 為了更方便的將各種東西塞入data, lz創(chuàng)造了一個(gè) Param.
            試試boost.tuple?

            為了讓一個(gè)簽名接受不同類(lèi)型的tuple/Param, 再將它們?nèi)胍粋€(gè)any/void*。


            舊瓶新酒~~~  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 13:38 Kevin Lynx

            @OwnWaterloo
            對(duì),就是你說(shuō)的這個(gè)意思。我也記得有個(gè)tuple這個(gè)東西。但是我一般不用boost,太大,太多??梢杂脕?lái)學(xué)習(xí)。:)
              回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 13:53 OwnWaterloo

            @Kevin Lynx
            嗯,boost確實(shí)有點(diǎn)重……
            那么我們拋棄boost::tuple, 使用std::tr1::tuple吧~~~

            不過(guò)any…… 這可憐的家伙沒(méi)被采納…… 得自己實(shí)現(xiàn)……  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 14:58 OwnWaterloo

            光顧著說(shuō)笑了…… 說(shuō)點(diǎn)正事。
            這樣做算不上"降低耦合"吧?

            void OnE1(tuple<e11,...> );
            void OnE2(tuple<e21,...> );
            void OnE3(tuple<e31,...> );

            和:

            void OnEvent(int e, any );

            的耦合性不是完全一樣么?
            log和UI依然必須"協(xié)商"每個(gè)事件的參數(shù)是怎樣的。


            只是后一種方式, 將通信的接口納入一個(gè)之中, 而不是每產(chǎn)生一個(gè)新事件就添加一個(gè), 也就是說(shuō), 這個(gè)接口可以完全固定下來(lái)了, 不會(huì)再發(fā)生變化。

              回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 15:31 Kevin Lynx

            @OwnWaterloo
            是啊。嚴(yán)格來(lái)說(shuō),不算降低耦合。因?yàn)閁I和邏輯層確實(shí)得協(xié)商設(shè)置哪些通知事件。不過(guò),反正這個(gè)邏輯模塊本身就是要通知UI事件觸發(fā)的。這樣做之后,邏輯模塊不需要管UI是否處理,只需要通知。在任何地方想怎樣通知就通知。整個(gè)程序換了UI后,邏輯層也不需要改,只改UI的通知處理即可。
            另一方面,如果使用
            void OnE1(tuple<e11,...> );
            void OnE2(tuple<e21,...> );
            void OnE3(tuple<e31,...> );
            這種方式,就會(huì)涉及到添加很多通知接口。這個(gè)負(fù)責(zé)通信的中間層就會(huì)越來(lái)越龐大。雖然,OnEvent(int e, any );這個(gè)方式會(huì)導(dǎo)致添加越來(lái)越多的事件類(lèi)型定義,但總比添加一個(gè)OnEn好吧?:)
            很少做這種UI比較復(fù)雜的應(yīng)用程序,不知道其他人有沒(méi)有好的模塊架構(gòu)方法。實(shí)在不想把UI和邏輯揉得那么緊??催^(guò)一些人直接在MFC的OnXXX里寫(xiě)一堆邏輯代碼就覺(jué)得受不了。 我現(xiàn)在做的東西里就包含MFC和控制臺(tái)兩套UI,甚至在GUI方面差點(diǎn)換到bcb。
              回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 15:50 OwnWaterloo

            @Kevin Lynx
            我說(shuō)說(shuō)我的看法啊, 你看看是否合理。

            將:
            void OnE1(tuple<e11,...> );
            void OnE2(tuple<e21,...> );
            void OnE3(tuple<e31,...> );

            轉(zhuǎn)化為:
            OnEvent(int e, any );

            是合理的,因?yàn)檫@樣做可以很好的適應(yīng)"增加event種類(lèi)"這一變化。
            對(duì)"需要增加很多event"或者"event暫時(shí)未知"的情況, 是很有用的。
            也算是降低了耦合度吧, 因?yàn)?br>>邏輯層也不需要改,只改UI的通知處理即可。
            嗯……

            相比一些其他的很?chē)?yán)格的抽象方式, 比如將每個(gè)OnE1設(shè)置為純虛…… 那簡(jiǎn)直是自討苦吃……
            一旦增加一個(gè)OnEx的純虛, ui代碼就需要改。
            如果不是純虛, 或者使用OnEvent(int e, any );就有一個(gè)"緩合"的機(jī)會(huì), 可以慢慢來(lái)~~~



            但是, 我有一個(gè)猜測(cè), 你看看對(duì)不對(duì):
            OnEvent(int e, any );
            添加這一層, 總工作量不會(huì)有絲毫減少, 甚至?xí)黾印?br>有可能ui端會(huì):
            switch (e)

            如果e的種類(lèi)繼續(xù)增加, 還可能在ui端繼續(xù)轉(zhuǎn)變?yōu)椋?br>ReplyE1(tuple<E11, ... > );
            ReplyE2(tuple<E21, ... > );
            ReplyE3(tuple<E31, ... > );


            再次申明啊, 我覺(jué)得OnEvent(int e, any );是有好處的。
            logic和ui通過(guò)這個(gè)通信。
            logic內(nèi)部是否NotifyE1,NotifyE2的形式? UI是否采用RE1,RE2的形式?
            這個(gè)是完全解耦了。
            只是數(shù)據(jù)格式始終解不了。

            >看過(guò)一些人直接在MFC的OnXXX里寫(xiě)一堆邏輯代碼就覺(jué)得受不了。
            嗯…… 我曾經(jīng)就寫(xiě)過(guò)讓你受不了的代碼~~~
            當(dāng)然, 現(xiàn)在我也受不了那代碼了……
            但是呢, 現(xiàn)在又沒(méi)機(jī)會(huì)去做這種logic,ui分離的事, 只是猜測(cè)OnEvent(int e, any );會(huì)使得總代碼量增加。
            希望能得到你的經(jīng)驗(yàn)之談~~~

              回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-23 16:13 Kevin Lynx

            @OwnWaterloo
            其實(shí)工作量這事,本來(lái)也就沒(méi)有被減少。就工作量(代碼量)這個(gè)角度來(lái)比較兩者的話。OnE1 OnE2和OnEvent(以后討論就說(shuō)前者后者)比較而言,在增加新的事件通知時(shí),前者需要增加通信層接口聲明(也就是那個(gè)被UI繼承的基類(lèi));后者需要從Param逐個(gè)取數(shù)據(jù),前者是直接在參數(shù)里,如果前者也使用Param或者tuple來(lái)組織參數(shù),也免不了解參數(shù)。

            我覺(jué)得后者較前者讓人爽的好處就是:永遠(yuǎn)不需要改這個(gè)中間通信層。

            說(shuō)下我現(xiàn)在是怎么派發(fā)通知的,這個(gè)其實(shí)也被放在這個(gè)通信中間層:
            class OpNotify
            {
            typedef void (*HandleNotifyFnT)( any *data );
            public:
            AddNotifyHandler( long event_id, HandleNotifyFnT fn );
            void Notify( long event_id, any data );
            private:
            std::map<long, HandleNotifyFnT> handleFuncTable;
            };
            UI層需要注冊(cè)處理事件通知的函數(shù)到handleFuncTable里。邏輯層每次派發(fā)事件通知時(shí),調(diào)用OpNotify::Notify,這個(gè)函數(shù)簡(jiǎn)單地從handleFuncTable里找對(duì)應(yīng)的處理函數(shù)。
            這個(gè)樣子之后,避開(kāi)了switch...case。誰(shuí)都知道,隨著事件類(lèi)型的增加,switch...case也將急速膨脹。進(jìn)一步地,通信中間層永遠(yuǎn)不需要修改了。

            現(xiàn)在邏輯層派發(fā)事件通知時(shí):
            OP_NOTIFY( NT_ENTER_RGN, any( create_param( player, rgn_id ) ) );
            // OP_NOTIFY被定義為OpNotify::Notify

            UI層只需要定義NT_ENTER_RGN的處理函數(shù),并注冊(cè)到OpNotify,該處理函數(shù)大致為:
            void HandleEnterRgn( any *data )
            {
            typedef Param2<Player, long> ParamType;
            ParamType *p = any_cast<ParamType>( data );
            Player *player = p->p1;
            long rgn_id = p->p2;
            }

              回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-24 01:54 qinqing

            很好,受益了  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-24 01:55 qinqing

            這種代碼的設(shè)計(jì)是沒(méi)有最好方法的,依賴(lài)于語(yǔ)言的特性  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-24 09:03 欲三更

            1 這個(gè)東西能實(shí)現(xiàn)邏輯層和UI層在不同線程里的事件機(jī)制? 沒(méi)看出來(lái).

            2 這么執(zhí)著的降低耦合,應(yīng)該是比較大的程序里才有用吧? 但是模板機(jī)制只能在一個(gè)模塊里使用,這個(gè)限制還是比較大的.

            3 把耦合降到最小,似乎需要加一層"事件解釋機(jī)制". 邏輯和UI的最大耦合不在于回調(diào)的形式上,而在于事件解釋機(jī)制的分散.邏輯層發(fā)生的事件是諸如"底層數(shù)據(jù)更新"的事件,UI層的響應(yīng)是"ListView重載入" 這樣的, 把這些之間的解釋和映射放到一起,無(wú)論什么形式的回調(diào)機(jī)制都可以.

            純個(gè)人感覺(jué), 不要相信:)  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-25 15:48 expter

            太花哨了。。

            先看看,在慢慢消化  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-08-31 12:27 codespy

            boost不是有信號(hào)槽機(jī)制嗎,這個(gè)機(jī)制不就是用于解決此問(wèn)題的嗎?  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2009-10-09 14:14 starwing

            這個(gè)問(wèn)題,其實(shí)不一定非要是“協(xié)商”??梢允莡i規(guī)定好了事件,讓logic來(lái)遵守(WinProc,或者gtk的模式),又或者是logic規(guī)定好了接口,讓ui來(lái)調(diào)用。總歸有個(gè)主次。當(dāng)然,也可以把這個(gè)主次去掉,把協(xié)商實(shí)體化,做成controler,也就是MVC了。

            針對(duì)這個(gè)問(wèn)題來(lái)說(shuō),其實(shí)可以將這個(gè)“通道”抽象出來(lái)。由ui在其中注冊(cè)事件,由logic查詢(xún)可用的事件,然后hook,然后由ui來(lái)調(diào)用hook,這樣恐怕能更模塊化一點(diǎn),不過(guò)這個(gè)就是純C的方案了。如果是要面向?qū)ο螅梢宰屚ǖ辣A魎i和logic類(lèi),然后ui和logic各保留通道類(lèi),然后就跟剛才一樣,由ui注冊(cè)事件,由logic來(lái)注冊(cè)hook了。優(yōu)勢(shì)在于,可以一個(gè)logic管理多個(gè)ui,可以一個(gè)ui由多個(gè)logic注冊(cè)hook(因?yàn)閔ook順次執(zhí)行),也可以多個(gè)logic對(duì)多個(gè)ui協(xié)商。并且因?yàn)閘ogic是要查詢(xún)以后才能夠hook,擴(kuò)展性會(huì)變強(qiáng),而且也是真正減少了耦合。

            熟悉gtk的人可能看出來(lái)了,這就是gtk的signal。我覺(jué)得,這種設(shè)計(jì)才是比較低耦合的。

            優(yōu)勢(shì):低耦合,signal做好了則所有的ui和logic都只需要注冊(cè)-查詢(xún)-hook,十分方便,減少了工作量(因?yàn)椴辉傩枰粋€(gè)超大的switch了)
            劣勢(shì):signal可能需要一定的代碼量。它本身需要一個(gè)類(lèi)型系統(tǒng)作為基礎(chǔ)(gtk使用自己的GType和不定參數(shù)解決的這個(gè)問(wèn)題),還有最致命的:它有比較嚴(yán)重的效率問(wèn)題(使用字符串注冊(cè)event,雖然可以使用GQuark技術(shù)加速,么但是速度仍然比不上直接用int。為什么不用int呢?因?yàn)榧热皇亲?cè)-查詢(xún),那么真正的事件號(hào)就是可變的,因此沒(méi)辦法直接將事件號(hào)寫(xiě)死進(jìn)程序里面)。  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2010-07-17 11:51 li song

            這種方法主要是通過(guò)組合出一種函數(shù)類(lèi)型,來(lái)實(shí)現(xiàn)偏特化。

            是模板特化。。。

            哥子來(lái)看你了,老哥們  回復(fù)  更多評(píng)論   

            # re: 低耦合模塊間的通信組件:兩個(gè)模板 2013-03-02 18:23 yzm

            哥們你太牛了啊~!  回復(fù)  更多評(píng)論   

            国产成人久久精品一区二区三区| 日本福利片国产午夜久久| 精品多毛少妇人妻AV免费久久 | 精品久久人人妻人人做精品| 久久久精品人妻一区二区三区蜜桃 | 欧美午夜精品久久久久免费视| 亚洲精品乱码久久久久久蜜桃 | 亚洲国产精品久久久久婷婷软件| 久久99久国产麻精品66| 无码任你躁久久久久久老妇| 久久久久久亚洲精品不卡| 99国内精品久久久久久久| 国产国产成人精品久久| 青草国产精品久久久久久| 久久久久久国产精品无码下载 | 亚洲国产欧美国产综合久久| 国产美女亚洲精品久久久综合| 亚洲AⅤ优女AV综合久久久| 亚洲国产天堂久久久久久| 久久国产成人| 久久久久国产精品嫩草影院| 久久亚洲精品无码播放| 国产免费久久精品99re丫y| 亚洲午夜久久久| 国产亚洲精久久久久久无码77777 国产亚洲精品久久久久秋霞 | 久久综合色之久久综合| 亚洲国产精品狼友中文久久久| 久久亚洲电影| 久久久噜噜噜久久中文字幕色伊伊 | 国产精品久久久久久久| 久久线看观看精品香蕉国产| 国产99久久久久久免费看| 久久er国产精品免费观看8| 亚洲伊人久久成综合人影院 | 久久久久亚洲AV无码专区网站| 久久亚洲中文字幕精品一区四 | 久久久久久久人妻无码中文字幕爆| 国产精品女同久久久久电影院| 91久久婷婷国产综合精品青草| 色综合色天天久久婷婷基地| 久久中文字幕视频、最近更新|