青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
數(shù)據(jù)加載中……

業(yè)務(wù)邏輯的強(qiáng)類型化

       業(yè)務(wù)邏輯中,很多邏輯上不同類型的東西,到了編程語言中,時常會退化成一種類型。一個最簡單的例子就是貨幣。通常在我們編程時,采用一種類型,如double(有些系統(tǒng)中有專門的Currency類型,為了簡便起見,這里使用double),來表示貨幣。

       但是,隨之而來的就是幣種的問題。不同的幣種間存在換算,也就是匯率的問題。比如我們有RMB和USD兩種貨幣,分別表示人民幣和美元。盡管都是貨幣(在代碼中有相同的類型),我們卻不能對他們直接賦值:

double rmb_;
double usd_=100;
rmb_=usd_;        //絕對不行,100美元可相當(dāng)于768元人民幣,盡管人民幣在升值
必須進(jìn)行匯率換算:
rmb_=usd_*e_rate;

     e_rate就是匯率。這個誰都清楚。在邏輯上,100美元和768元人民幣是等價的(假設(shè)今天的匯率是7.68),是可以兌換的。但在軟件中,我們不能簡單的賦值了事,必須做換算。現(xiàn)在我們希望用代碼直接表現(xiàn)邏輯上的意義,也就是用賦值操作:=,實現(xiàn)貨幣間的換算,該怎么做呢?啊對,沒錯,操作符重載。

    我們可以重載operator=操作符,使其具備匯率換算的功能。(或許有人會提出異議,改變一個操作符已有的語義,是否違背大師們的教誨。但我個人認(rèn)為,語義應(yīng)當(dāng)遵從業(yè)務(wù)邏輯,既然按照邏輯含義進(jìn)行重載,不應(yīng)該引發(fā)什么糾紛。否則還需要重載干嗎?)但問題是,重載依賴于不同的類型,double operator=(double)的操作符定義是默認(rèn)的,已經(jīng)存在,無法以相同形式重載。再說,即便是可以,復(fù)制對象和被賦值對象的類型相同,如何區(qū)分兩種類型的轉(zhuǎn)換呢?

    很明顯,我們需要新的類型。typedef肯定是沒指望的,因為它僅僅為一個類型起別名,并沒有產(chǎn)生新的類型。所以,我們只能求助于類。我們可以以如下方式定義各種不同的貨幣類:
class RMB
{
public:
    double    _val;
};
class USD
{
public:
    double    _val;
};

這樣,便可以針對不同貨幣重載operator=:
class RMB
{
public:
    RMB operator=(const RMB& v) {
        _val=v._val;
    }
    RMB operator=(const USD& v) {
        _val=v._val*e_rate;    //貨幣換算
    }
public:
    double    _val;
};
class USD
{
public:
    USD operator=(const USD& v) {
        _val=v._val;
    }
    USD operator=(const RMB & v) {
        _val=v._val/e_rate;    //貨幣換算
    }
public:
    double    _val;
};

這樣,我們便可以對兩種貨幣賦值了:
RMB    rmb_;
USD    usd_;
rmb_=usd_;        //帶貨幣換算的賦值操作

        根據(jù)這個方法,我們一直往下推,可以構(gòu)造出各種各樣的貨幣,并且定義它們之間的轉(zhuǎn)換:
class UKP    //英鎊
{…}
class JPD    //日元
{…}

        不過有個問題,如果有10中貨幣,我們必須定義100個operator=的重載,而且都是些重復(fù)代碼。這樣太蠢了。得采用更好的方法才能實現(xiàn)我們的理想。注意觀察,每個貨幣類的代碼都符合同一種模式,有很強(qiáng)的規(guī)律性。看出來了吧,這種情況非常適合使用C++的超級武器——模板。沒錯,說做就做:
template
<int CurrType>
class Currency
{
public:
    double    _val;
};

        注意看,這里非常規(guī)地使用了模板的一個特性:非類型模板參數(shù),就是那個int CurrType。模板參數(shù)通常都是一個類型,比如int什么的。但也可以是一個非類型的模板參數(shù),就象這里的CurrType。傳統(tǒng)上,非類型模板參數(shù)用于傳遞一個靜態(tài)的值,用來構(gòu)造模板類。但在這里,這個模板參數(shù)并沒有被模板使用,也永遠(yuǎn)不會被使用。這個模板參數(shù)的作用就是“制造類型”:
typedef    Currency
<0>    RMB;    //人民幣
typedef    Currency
<1>    USD;    //美元
typedef    Currency
<2>    UKP;    //英鎊
typedef    Currency
<3>    JPD;    //日元

typedef本身不會產(chǎn)生新的類型,但是這里Currency
<n>已經(jīng)是完全不同的類型了。當(dāng)一個模板被實例化成一個類的時候,只要模板參數(shù)的實參有所不同,便是一個不同的類型。我們利用了模板的這個特性,憑空制造出任意多個結(jié)構(gòu)完全相同,但卻是完全獨立的類型。
好,下一步,便是重載operator=操作符。當(dāng)然不能再做為每一對貨幣類型重載operator=的蠢事了。用一個成員函數(shù)模板就可以解決問題:
double e_rate[10][10];        //匯率表

template
<int CurrType>
class Currency
{
public:
    template
<int ct2>
    Currency
<CurrType>& operator=(count Currency<ct2>& v) {
        _val=v._val * e_rate[ct2][CurrType];    //找出匯率表中相應(yīng)的匯率,
                                                // 計算并賦值
    }
public:
    double    _val;
};

     操作符operator=的代碼中,賦值對象v的值乘上一個匯率,這個匯率存放在匯率表中,通過模板參數(shù)CurrType和ct2檢索(當(dāng)然匯率表得足夠大)。這樣,我們便可以隨意地賦值,而無須關(guān)心貨幣轉(zhuǎn)換的問題了:

///初始化匯率表
e_rate[0][0]=1;
e_rate[1][0]=7.68;

//使用貨幣
USD    usd_;
UKP    ukp_;
JPD    jpd_;

jpd_=usd_=ukp=rmb_;    //成功!一切順心。
      需要說明的是,匯率表并沒有在聲明時就初始化,是考慮到匯率經(jīng)常變動,不應(yīng)當(dāng)作為常量寫死在代碼中。更進(jìn)一步可以使用一個類封裝成可變大小的匯率表,甚至可以用某個文件或數(shù)據(jù)庫對其初始化。

問題當(dāng)然還有,貨幣是要參與運算的,否則沒有什么用處。所以,我們還得使這些貨幣具備基本的計算能力。貨幣的計算,根據(jù)業(yè)務(wù)邏輯大致應(yīng)具備以下能力:
1.    +、-:兩種貨幣的加法和減法,允許不同種貨幣參與計算,必須考慮轉(zhuǎn)換操作,返回做操作數(shù)類型;
2.    *、/:貨幣乘上或除以一個標(biāo)量值,這里設(shè)定為double。但兩種貨幣不能相乘或相除。
3.    ==、!=:比較兩種貨幣,允許不同種貨幣參與比較,但必須考慮轉(zhuǎn)換操作。
     
       還有其他的操作,暫不做考慮,畢竟這里的目的不是開發(fā)一個完整的貨幣系統(tǒng)。為了編碼上的方便,這里同時還定義了四則運算的賦值版本:+=、-=、*=、/=。為了節(jié)省篇幅,這里只展示+、*和==的代碼,其他代碼類推:
template
<int ty, int tp>
inline bool operator==(currency
<ty>& c1, const currency<tp>& c2) {
    return    c1._val==c2._val*curr_rate[tp][ty];
}

template
<int ty, int tp>
inline currency
<ty>& operator+=(currency<ty>& c1, const currency<tp>& c2) {
    c1._val+=c2._val*curr_rate[tp][ty];
    return    c1;
}
template
<int ty, int tp>
inline currency
<ty> operator+(currency<ty>& c1, const currency<tp>& c2) {
    currency
<ty> t(c1);
    t+=c2;
    return    t;
}

      請注意==和+操作符中的的貨幣轉(zhuǎn)換運算,每次都是將第二操作數(shù)貨幣轉(zhuǎn)換成第一操作數(shù)貨幣后再進(jìn)行運算操作。第一參數(shù)和第二參數(shù)的類型不同,因此允許不同貨幣進(jìn)行計算。這可以進(jìn)一步簡化代碼,完全以邏輯的方式編程。
template
<int ty>
inline currency
<ty>& operator*=(currency<ty>& c1, const double q) {
    c1._val*=q;
    return    c1;
}
template
<int ty>
inline currency
<ty> operator*(currency<ty>& c1, const double q) {
    currency
<T, ty>    t(c1);
    t*=q;
    return    t;
}

template
<int ty>
inline currency
<ty>& operator*=(const double q,currency<ty>& c1) {
    return    operator*=(c1, q);
}
template
<int ty>
inline currency
<ty> operator*(const double q,currency<ty>& c1) {
    return    operator*(c1, q);
}


      *操作符的參數(shù)只有一個是貨幣類型,另一個是double類型,表示數(shù)量。只有貨幣乘上數(shù)量才有意義,不是嗎?*操作符包括兩個版本,一個貨幣在前,數(shù)量在后;另一個數(shù)量在前,貨幣在后。為的是適應(yīng)rmb_*1.4和1.4*rmb_兩種不同的寫法,算法是完全一樣的。
現(xiàn)在,貨幣可以運算了:
usd_=usd_*3;                      //同種貨幣運算
ukp_=rmb_*2.5;                 ///計算後直接賦值給另一種貨幣
jpd_=ukp_=rmb_+usd_;     ///同上,但有四種貨幣參與運算
現(xiàn)在,貨幣運算非常方便了,不需要考慮貨幣種類,貨幣的轉(zhuǎn)換是自動的,無需額外代碼。在簡化代碼的同時,也提供了操作上的約束,比如:
ukp_=rmb_*usd_;    ///編譯錯誤。貨幣乘上另一種貨幣無意義!!!

       這句代碼會引發(fā)編譯錯誤,因為我們沒有為兩種貨幣相乘提供*的重載。很明顯,一種貨幣與另一種貨幣相乘是根本沒有意義的。這里通過靜態(tài)的重載類型檢查,對施加在貨幣上的運算做出約束。促使違背邏輯的代碼在第一時間被攔截,避免出現(xiàn)運行時錯誤。要知道,兩種貨幣相乘,賦給另一個貨幣的錯誤是非常隱蔽的,只有盤庫或結(jié)賬的時候才會發(fā)現(xiàn)。

       很好,這里我們利用了C++模板的一些特殊機(jī)制,以及操作符模板、操作符重載等技術(shù),開發(fā)一個貨幣系統(tǒng)。這個系統(tǒng)可以用最簡潔的語句實現(xiàn)各種貨幣的計算和轉(zhuǎn)換功能。同時,還利用重載機(jī)制的強(qiáng)類型特性,提供了符合業(yè)務(wù)邏輯的操作約束。

      貨幣運算只是一個簡單的案例,但相關(guān)的技術(shù)可以進(jìn)一步推廣到更復(fù)雜的領(lǐng)域中。而且業(yè)務(wù)越復(fù)雜,所得到的收益越多。因此,充分理解并運用C++所帶來的泛型編程功能,可以大大簡化軟件的開發(fā)、減少代碼的錯誤,降低開發(fā)的成本。

       這種技術(shù)適合用在一些邏輯上存在差異,但在物理上具備相同特征的實體上。一方面使這些實體在代碼中強(qiáng)類型化,以獲得重載和類型檢測能力。由于代碼中邏輯實體的對應(yīng)類型強(qiáng)類型化,是我們可以通過重載和靜態(tài)類型檢測等技術(shù)手段,實現(xiàn)僅使用語言提供的要素,在代碼中直接構(gòu)造業(yè)務(wù)模型的能力。但手工對每一個邏輯實體進(jìn)行強(qiáng)類型化,是費力的和瑣碎的,并且存在著大量的重復(fù)勞動。此時,我們可以利用模板的抽象能力,反過來利用邏輯實體在物理上的共同特性,一次性構(gòu)建抽象的模板,并利用模板實例化的一些特性,很方便地構(gòu)造新的類型(僅僅一個typedef)。
     這種技術(shù)進(jìn)一步擴(kuò)展后,可以有更高級的應(yīng)用。一個經(jīng)典的范例就是實現(xiàn)編譯期的量綱分析。在Template Meta-programming一書中,對此有詳細(xì)的講解

================================================================================================
作為一個好事者,我希望能夠給我周邊的人講解這種技術(shù)。他們對C++很不熟悉,但熟悉C#。于是,我打算把這種技術(shù)移植到C#中,以便於講解。說做就做。
我建了一個C#項目,把代碼拷貝過去,然后著手修改,這樣可以省些事。我立刻便遇到了問題。C#有泛型,相當(dāng)于模板,但不支持非類型泛型參數(shù),即int CurrType,只允許用一個類型作為泛型參數(shù)。這樣我們就不能使用C++中耍的手法了(typedef currency
<n>)。退而求其次,直接用類實現(xiàn)貨幣類型:
class RMB
{
public double _val;
}
class USD
{
public double _val;
}

這樣太繁瑣了,很多重復(fù)。我們可以用一個基類封裝_val,貨幣類從基類上繼承獲得:
class CurrBase
{
public double _val;
}
class RMB : CurrBase
{
}
class USD : CurrBase
{
}

貨幣類都是空的,它們的存在只是為了創(chuàng)建一個新的類型。
現(xiàn)在處理貨幣轉(zhuǎn)換問題。C#不能重載operator=,所以只能使用一個helper函數(shù)泛型asign代替:
class utility
{
     public static void asign
<T1, T2>(T1 c1, T2 c2)
         where T1 : CurrBase
         where T2 : CurrBase
     {
         c1._val = c2._val * utility.e_rate[c2.CurID(),c1.CurID()];
     }
}

這個asign函數(shù)是個泛型,泛型參數(shù)分別代表了兩個操作數(shù),函數(shù)中執(zhí)行了貨幣轉(zhuǎn)換。為了能夠在匯率表中檢索到相應(yīng)的匯率,我們必須為基類和貨幣類定義抽象函數(shù):
    public abstract class CurrBase
    {
        public double _val=0;
        public abstract int CurID();
    }
    public class RMB : CurrBase
    {
        public override int CurID()
        {
            return 0;
        }
}

基類中聲明了CurID()抽象方法,并在貨幣類中定義。這樣,便可以用統(tǒng)一的方式進(jìn)行貨幣轉(zhuǎn)換了:
asign(rmb_, usd_);
還行,盡管不那么漂亮,但也還算實用。不過,當(dāng)我多看了幾眼代碼后,便發(fā)現(xiàn)這里根本沒有必要使用泛型。完全可以利用OOP的多態(tài)實現(xiàn)同樣的功能:
     public static void asign(CurrBase c1, CurrBase c2)
     {
         c1._val = c2._val * utility.e_rate[c2.CurID(),c1.CurID()];
     }

不過也沒關(guān)系,使用方式還沒有變,代碼反而更簡單了。使用泛型畢竟不是我們的根本目的,對吧?
現(xiàn)在輪到運算符了。不過我不知該把泛型運算符定義在哪里。按C#文檔里的要求,運算符必須是類的static成員。但我的泛型運算符是針對許多個貨幣類的,定義在任何一個中,對其他類似乎不太公平。于是,我決定嘗試將其定義在基類里:
    public abstract class CurrBase
{
    …
        public static CurrBase operator+
<T1, T2>(T1 c1, T2 c2)
            where T1 : CurrBase
            where T2 : CurrBase
        {
            …
        }
}

編譯器立刻還我以顏色:操作符根本不能是泛型!好吧,不能就不能吧,繼續(xù)退而求其次,用OOP:
    public abstract class CurrBase
{
    …
        public static CurrBase operator+(CurrBase c1, CurrBase c2)
        {
            …
        }
}

不過,這次讓步讓得有點離譜。當(dāng)我寫下這樣的代碼時,編譯器居然不認(rèn)賬:
rmb_=rmb_+usd_;
錯誤信息是:錯誤 CS0266: 無法將類型“st_in_cs.CurrBase”隱式轉(zhuǎn)換為“st_in_cs.RMB”。存在一個顯式轉(zhuǎn)換(是否缺少強(qiáng)制轉(zhuǎn)換?)。
我非得采用強(qiáng)制類型轉(zhuǎn)換,才能過關(guān):
rmb_=(RMB)(rmb_+usd_);
太夸張了,這樣肯定不行。于是,我被迫在每個貨幣類中定義operator+:
class RMB : CurrBase
{

    public RMB operator+(RMB c1, USD c2)
    {
        …
    }
    public RMB operator+(RMB c1, UKP c2)
    {
        …
    }

}

這可不得了,我必須為每對貨幣類定義一個+操作符,+操作符的總數(shù)將會是貨幣類數(shù)量的平方!其他的操作符每個都是貨幣類數(shù)的平方。我可受不了!
好在,可愛的OOP為我們提供了一根稻草,使得每個貨幣類的每個操作符只需定義一個:
class RMB : CurrBase
{

    public RMB operator+(RMB c1, CurrBase c2)
    {
        …
    }

}
這樣,任何貨幣類都可以作為第二操作數(shù)參與運算,而操作符只需定義一個。這樣的工作量,對于一個逆來順受的程序員而言,還是可以接受的。很好,代碼不出錯了:
rmb_=rmb_+usd_;
但當(dāng)我寫下如下代碼時,編譯器又開始抱怨了:
ukp_ = rmb_ + usd_;
還是要求顯示轉(zhuǎn)換,除非我們?yōu)閁KP定義隱式類型轉(zhuǎn)換操作符:
class UKP
{

    public static implicit operator UKP(RMB v)
    {
        …
    }

}
光有RMB的不行啊,還得有USD的、JPD…。不過這樣的話,我們必須為每一個貨幣類定義所有其它貨幣類的類型轉(zhuǎn)換操作符。又是一個組合爆炸。到這里,我已經(jīng)黔驢技窮了。誰讓C#不支持=操作符重載和操作符模板化呢。沒辦法,只能忍著點了。
不過,如果我們能夠降低點要求,事情還是有轉(zhuǎn)機(jī)的。如果我們不通過操作符,而是采用static成員方法,進(jìn)行貨幣的運算的話,就可以省去很多代碼了:
    public class utility
    {
        public static T1 asign
<T1, T2>(T1 c1, T2 c2)
            where T1 : CurrBase, new()
            where T2 : CurrBase
        {
            c1._val = c2._val * utility.curr_rate[c2.CurID(),c1.CurID()];
            return    c1;
        }
        public static T1 add
<T1, T2>(T1 c1, T2 c2)
            where T1 : CurrBase, new()
            where T2 : CurrBase
        {
            T1 t=new T1();
            t._val=c1._val + c2._val *
                utility.curr_rate[c2.CurID(),c1.CurID()];
            return t;
        }
        …
}
這里,我還是使用了泛型,因為這些函數(shù)需要返回一個值,只有使用泛型,才能返回一個明確的類型,以避免強(qiáng)制轉(zhuǎn)換的要求。于是,賦值和計算的代碼就成了:
asign(jpd_, asign(ukp_, add(rmb_, usd_)));//也就是jpd_=ukp_=rmb_+usd_
的確是難看了點,但是為了能夠少寫點代碼,這也只能將就了。

好了,我盡了最大的努力,試圖在C#中實現(xiàn)強(qiáng)類型、可計算的貨幣系統(tǒng)。盡管最終我可以在C#中開發(fā)出一組與C++具有相同效果的貨幣類(除了賦值操作以外),但需要我編寫大量的代碼,實現(xiàn)各種計算操作,以及貨幣類之間的類型轉(zhuǎn)換操作(組合爆炸)。相比C++中總共200來行代碼,的確復(fù)雜、臃腫得多。
我并不希望把這篇文章寫成“C++ vs C#”,(盡管我很高興看到C++比C#強(qiáng)?)。我希望通過對這樣一個代碼優(yōu)化任務(wù),顯示不同技術(shù)運用產(chǎn)生的結(jié)果。同時,也可以通過這兩種實現(xiàn)嘗試的對比,了解泛型編程的作用,以及泛型編程對語言提出的要求。

毋庸置疑,C++采用了純粹的泛型編程,因此可以對問題進(jìn)行高度抽象。并利用問題所提供的每一點有助于抽象的信息,以最簡的形式對問題建模。而作為以O(shè)OP為核心的語言C#,對泛型的支持很弱。更重要的是,C#的泛型對泛型參數(shù)的運用嚴(yán)重依賴於泛型參數(shù)的約束(where)。如果沒有where,C#將泛型參數(shù)作為Object類型處理,此時泛型參數(shù)沒有意義(我無法訪問該類型的成員)。如果有了where,C#要求泛型參數(shù)必須同where中指定的類型有繼承關(guān)系(如asign中的T1必須是CurrBase的繼承類)。而泛型函數(shù)中對泛型參數(shù)的使用也局限在約束類型(即CurrBase)上。于是,我們可以直接用以基類(CurrBase)為參數(shù)的asign函數(shù)代替泛型版本的asign。由于C#對泛型參數(shù)的繼承性要求,使得泛型被困住了手腳,無法發(fā)揮應(yīng)用的作用。正由于這些問題,C++才采用了現(xiàn)在模板的形式,而沒有采用同C#一樣的泛型模式。

或許有人會說,既然OOP能解決問題(asign最初不需要泛型也行,但最終還需要泛型來控制返回值的類型),為什么還要GP呢?
對于這個問題,前面也給出了答案。由于C#的泛型不支持非類型泛型參數(shù),因此迫使我們使用傳統(tǒng)OOP的手段:利用基類實現(xiàn)貨幣類的實現(xiàn),定義貨幣類來創(chuàng)建新類型,使貨幣強(qiáng)類型化,利用虛函數(shù)提供貨幣獨有信息。僅這一層面,OOP方式已經(jīng)大大不如GP方式了,GP僅定義了一個模板,所有的貨幣類型都是通過typedef一句語句產(chǎn)生,無需更多的代碼。而OOP方式要求必須為每一個貨幣編寫一個類,代碼量明顯多于GP方式。

此后,C++通過重載一組操作符模板,實現(xiàn)貨幣的運算。而貨幣模板以及生成貨幣類型的typedef都無須任何改變。而在C#中,由于不支持泛型操作符,被迫定義大量的特定于類型的操作符。所有運算操作符,在每個貨幣類中都必須重載一次。而轉(zhuǎn)型操作符,則必須在每個貨幣類中重載n-1次。
換句話說,有n種貨幣,有m個操作符(包括轉(zhuǎn)型操作符),那么就需要定義n+1個類(包括基類),n×m+n×(n-1)個操作符。假設(shè)n=10,m=10,那么總共需要11個類定義,190個操作符重載!如果每個類定義需要20行代碼,而每個操作符重載需要5行代碼,那么總共需要1170行代碼。如果貨幣數(shù)量增加,總的代碼數(shù)將以幾何級數(shù)的方式增長。
上面的計算表明,盡管OOP可以解決問題,實現(xiàn)我們的目標(biāo),但所帶來的開發(fā)量和維護(hù)量卻是難以承受的。而且,OOP的方式擴(kuò)展非常困難,隨著系統(tǒng)規(guī)模的擴(kuò)大,擴(kuò)展將越來越困難。所有這些都表明一點,盡管OOP是軟件工程的明星,但在實際情況下,很多地方存在著OOP無法解決或難以解決的問題。這也就是為什么業(yè)界的先鋒人物不斷拓展和強(qiáng)化泛型編程的原因。

posted on 2008-07-27 17:10 肥仔 閱讀(374) 評論(0)  編輯 收藏 引用 所屬分類: C++ 模板

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲欧美激情视频| 欧美18av| 一区二区激情| 亚洲精品久久| 亚洲国产成人av好男人在线观看| 极品尤物av久久免费看| 国产精品日本一区二区| 亚洲精品在线三区| 久久精品亚洲热| 欧美午夜精品一区| 日韩网站在线看片你懂的| 一区免费视频| 国产精品免费aⅴ片在线观看| 99精品免费| 免费成人激情视频| 亚洲精品日韩在线观看| 亚洲先锋成人| 欧美精品午夜| 亚洲成在线观看| 亚洲日本va午夜在线电影| 亚洲久久成人| 亚洲精品视频免费在线观看| 欧美—级在线免费片| 亚洲欧洲精品一区| 亚洲成人在线视频播放| 日韩午夜免费视频| 久久理论片午夜琪琪电影网| 久久久久久久精| 久久丁香综合五月国产三级网站| 欧美二区在线| 91久久精品一区二区别| 一区二区三区产品免费精品久久75 | 欧美不卡一卡二卡免费版| 中日韩视频在线观看| 亚洲第一主播视频| 国产精品国产a级| 国产精品乱码久久久久久| 一区二区三区四区在线| 亚洲欧美激情在线视频| 亚洲国产mv| 亚洲国产精品ⅴa在线观看 | 亚洲欧美日韩成人高清在线一区| 亚洲一区二区高清视频| 久久国产综合精品| 欧美激情bt| 亚洲三级国产| 欧美日韩美女在线| 久久精品国产99国产精品| 国产精品久久久久久久午夜片| 国产精品一区亚洲| 亚洲日本视频| 久久精品亚洲精品| 牛牛精品成人免费视频| 亚洲一区欧美| 亚洲电影免费观看高清完整版在线观看 | 亚洲在线一区| 国产精品一区一区| 欧美一区二区三区在线| 亚洲国产精品黑人久久久| 国产精品资源| 亚洲永久网站| 一本色道久久88综合亚洲精品ⅰ | 亚洲国产精品久久久| 女女同性女同一区二区三区91| 1024成人| 久久av在线| 久久精品国产亚洲一区二区| 欧美午夜女人视频在线| 欧美不卡视频一区发布| 国产精品福利av| 免费日韩成人| 免费久久99精品国产| 性视频1819p久久| 久久一区免费| 狠狠色狠狠色综合| 午夜欧美精品久久久久久久| 亚洲精品永久免费| 欧美性猛交xxxx乱大交退制版| 欧美理论大片| 久久综合网络一区二区| 欧美freesex8一10精品| 亚洲图片在线观看| av成人免费观看| 亚洲激情第一区| 亚洲婷婷综合久久一本伊一区| 性18欧美另类| 亚洲福利在线看| 欧美一区二区三区男人的天堂| 欧美日韩激情小视频| 日韩一区二区精品| 亚洲国产精品精华液2区45| 久久综合亚州| 国产乱码精品一区二区三区忘忧草 | 亚洲理伦电影| 亚洲国产欧美日韩精品| 亚洲视频电影在线| 欧美偷拍一区二区| 欧美性做爰毛片| 亚洲视频久久| 女女同性精品视频| 香蕉久久国产| 制服丝袜亚洲播放| 欧美成人一区二区三区| 国产欧美日本一区二区三区| 亚洲美女中出| 欧美亚州一区二区三区| 亚洲大胆视频| 亚洲福利一区| 亚洲影音先锋| 欧美精品一区二区三区高清aⅴ| 亚洲欧洲一级| 亚洲视频网在线直播| a4yy欧美一区二区三区| 黄色日韩网站| 免费在线观看日韩欧美| 性欧美xxxx大乳国产app| 亚洲国产日韩欧美在线99| 久久久av网站| 亚洲视频电影图片偷拍一区| 国产精品v日韩精品| 欧美电影在线播放| 午夜在线成人av| 最近中文字幕日韩精品| 裸体女人亚洲精品一区| 亚洲欧洲精品一区| 午夜精品久久久久久99热软件| a91a精品视频在线观看| 欧美一区二区三区在| 亚洲高清视频的网址| 亚洲综合视频在线| 久久婷婷丁香| 日韩亚洲欧美精品| 午夜精品视频一区| 欧美成人免费大片| 亚洲一区二区三区在线观看视频| 国产亚洲综合精品| 欧美成人a视频| 亚洲欧美日韩在线观看a三区| 亚洲天堂免费观看| 国产亚洲免费的视频看| 一本色道久久综合精品竹菊 | 99在线精品免费视频九九视| 国产色产综合色产在线视频| 一区二区三区产品免费精品久久75| 国产一区二区久久精品| 国产精品男gay被猛男狂揉视频| 中文国产一区| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲成人在线免费| 久久综合中文字幕| 亚洲线精品一区二区三区八戒| 日韩小视频在线观看| 亚洲视频在线一区| 一本色道久久综合亚洲二区三区| 久久一二三四| 欧美诱惑福利视频| 久久精品国产第一区二区三区最新章节 | 午夜一区二区三区在线观看| 亚洲乱码日产精品bd| 国产在线日韩| 久热国产精品| 欧美金8天国| 亚洲主播在线| 亚洲精品专区| 在线日本欧美| 亚洲图片你懂的| 国产亚洲一级| 一区二区三区成人| 欧美成年人在线观看| 欧美亚洲系列| 性做久久久久久| 亚洲精品欧美精品| 亚洲欧美日韩另类| 久久国产精品久久久久久久久久| 嫩草影视亚洲| 亚洲国产成人tv| 久久美女性网| 欧美体内she精视频| 在线成人av| 久久久噜噜噜久久中文字幕色伊伊| 亚洲精品日韩在线观看| 欧美日韩在线看| 亚洲国产成人久久| 久久综合99re88久久爱| 欧美成人激情视频| 欧美精品麻豆| 一区二区免费在线播放| 亚洲美女91| 麻豆国产精品777777在线| 亚洲美女视频在线观看| 老司机一区二区| 国产精品实拍| 久久男女视频| 欧美a级在线| 久久久爽爽爽美女图片| 欧美国产日本在线| 欧美成人在线网站| 亚洲视频网在线直播| 欧美日韩一区二区三区| 国产综合第一页|