<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么我不推薦你用 if-else 做條件判斷?

          共 13005字,需瀏覽 27分鐘

           ·

          2021-10-21 09:53

          點擊“開發(fā)者技術前線”,選擇“星標”

          在看|星標|留言,? 真愛




          作者:DiDi516

          cnblogs.com/DiDi516/p/11787257.html

          前言

          物流行業(yè)中,通常會涉及到EDI報文(XML格式文件)傳輸和回執(zhí)接收,每發(fā)送一份EDI報文,后續(xù)都會收到與之關聯(lián)的回執(zhí)(標識該數(shù)據(jù)在第三方系統(tǒng)中的流轉狀態(tài))。

          這里枚舉幾種回執(zhí)類型:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999,系統(tǒng)在收到不同的回執(zhí)報文后,會執(zhí)行對應的業(yè)務邏輯處理。當然,實際業(yè)務場景并沒有那么籠統(tǒng),這里以回執(zhí)處理為演示案例

          模擬一個回執(zhí)類

          @Data
          public?class?Receipt?{

          ????/**
          ?????*?回執(zhí)信息
          ?????*/

          ????String?message;

          ????/**
          ?????*?回執(zhí)類型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)
          ?????*/

          ????String?type;

          }

          模擬一個回執(zhí)生成器

          public?class?ReceiptBuilder?{

          ????public?static?List?generateReceiptList(){
          ????????//直接模擬一堆回執(zhí)對象
          ????????List?receiptList?=?new?ArrayList<>();
          ????????receiptList.add(new?Receipt("我是MT2101回執(zhí)喔","MT2101"));
          ????????receiptList.add(new?Receipt("我是MT1101回執(zhí)喔","MT1101"));
          ????????receiptList.add(new?Receipt("我是MT8104回執(zhí)喔","MT8104"));
          ????????receiptList.add(new?Receipt("我是MT9999回執(zhí)喔","MT9999"));
          ????????//......????
          ????????return?receiptList;
          ????}
          }

          傳統(tǒng)做法-if-else分支

          List?receiptList?=?ReceiptBuilder.generateReceiptList();
          //循環(huán)處理
          for?(Receipt?receipt?:?receiptList)?{
          ????if?(StringUtils.equals("MT2101",receipt.getType()))?{
          ????????System.out.println("接收到MT2101回執(zhí)");
          ????????System.out.println("解析回執(zhí)內容");
          ????????System.out.println("執(zhí)行業(yè)務邏輯");
          ????}?else?if?(StringUtils.equals("MT1101",receipt.getType()))?{
          ????????System.out.println("接收到MT1101回執(zhí)");
          ????????System.out.println("解析回執(zhí)內容");
          ????????System.out.println("執(zhí)行業(yè)務邏輯");
          ????}?else?if?(StringUtils.equals("MT8104",receipt.getType()))?{
          ????????System.out.println("接收到MT8104回執(zhí)");
          ????????System.out.println("解析回執(zhí)內容");
          ????????System.out.println("執(zhí)行業(yè)務邏輯");
          ????}?else?if?(StringUtils.equals("MT9999",receipt.getType()))?{
          ????????System.out.println("接收到MT9999回執(zhí)");
          ????????System.out.println("解析回執(zhí)內容");
          ????????System.out.println("執(zhí)行業(yè)務邏輯");
          ????????System.out.println("推送郵件");
          ????}
          ????//?......未來可能還有好多個else?if
          }

          在遇到if-else的分支業(yè)務邏輯比較復雜時,我們都習慣于將其抽出一個方法或者封裝成一個對象去調用,這樣整個if-else結構就不會顯得太臃腫。

          就上面例子,當回執(zhí)的類型越來越多時,分支else if 就會越來越多,每增加一個回執(zhí)類型,就需要修改或添加if-else分支,違反了開閉原則(對擴展開放,對修改關閉)

          策略模式+Map字典

          我們知道, 策略模式的目的是封裝一系列的算法,它們具有共性,可以相互替換,也就是說讓算法獨立于使用它的客戶端而獨立變化,客戶端僅僅依賴于策略接口 。

          在上述場景中,我們可以把if-else分支的業(yè)務邏輯抽取為各種策略,但是不可避免的是依然需要客戶端寫一些if-else進行策略選擇的邏輯,我們可以將這段邏輯抽取到工廠類中去,這就是策略模式+簡單工廠,代碼如下

          策略接口

          /**
          ?*?@Description:?回執(zhí)處理策略接口
          ?*?@Auther:?wuzhazha
          ?*/

          public?interface?IReceiptHandleStrategy?{

          ????void?handleReceipt(Receipt?receipt);

          }

          策略接口實現(xiàn)類,也就是具體的處理者

          public?class?Mt2101ReceiptHandleStrategy?implements?IReceiptHandleStrategy?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt)?{
          ????????System.out.println("解析報文MT2101:"?+?receipt.getMessage());
          ????}

          }

          public?class?Mt1101ReceiptHandleStrategy?implements?IReceiptHandleStrategy?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt)?{
          ????????System.out.println("解析報文MT1101:"?+?receipt.getMessage());
          ????}

          }

          public?class?Mt8104ReceiptHandleStrategy?implements?IReceiptHandleStrategy?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt)?{
          ????????System.out.println("解析報文MT8104:"?+?receipt.getMessage());
          ????}

          }

          public?class?Mt9999ReceiptHandleStrategy?implements?IReceiptHandleStrategy?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt)?{
          ????????System.out.println("解析報文MT9999:"?+?receipt.getMessage());
          ????}

          }

          策略上下文類(策略接口的持有者)

          /**
          ?*?@Description:?上下文類,持有策略接口
          ?*?@Auther:?wuzhazha
          ?*/

          public?class?ReceiptStrategyContext?{

          ????private?IReceiptHandleStrategy?receiptHandleStrategy;

          ????/**
          ?????*?設置策略接口
          ?????*?@param?receiptHandleStrategy
          ?????*/

          ????public?void?setReceiptHandleStrategy(IReceiptHandleStrategy?receiptHandleStrategy)?{
          ????????this.receiptHandleStrategy?=?receiptHandleStrategy;
          ????}

          ????public?void?handleReceipt(Receipt?receipt){
          ????????if?(receiptHandleStrategy?!=?null)?{
          ?????????????receiptHandleStrategy.handleReceipt(receipt);???
          ????????}
          ????}
          }

          策略工廠

          /**
          ?*?@Description:?策略工廠
          ?*?@Auther:?wuzhazha
          ?*/

          public?class?ReceiptHandleStrategyFactory?{

          ????private?ReceiptHandleStrategyFactory(){}

          ????public?static?IReceiptHandleStrategy?getReceiptHandleStrategy(String?receiptType){
          ????????IReceiptHandleStrategy?receiptHandleStrategy?=?null;
          ????????if?(StringUtils.equals("MT2101",receiptType))?{
          ????????????receiptHandleStrategy?=?new?Mt2101ReceiptHandleStrategy();
          ????????}?else?if?(StringUtils.equals("MT8104",receiptType))?{
          ????????????receiptHandleStrategy?=?new?Mt8104ReceiptHandleStrategy();
          ????????}
          ????????return?receiptHandleStrategy;
          ????}
          }

          客戶端

          public?class?Client?{

          ????public?static?void?main(String[]?args)?{
          ????????//模擬回執(zhí)
          ????????List?receiptList?=?ReceiptBuilder.generateReceiptList();
          ????????//策略上下文
          ????????ReceiptStrategyContext?receiptStrategyContext?=?new?ReceiptStrategyContext();
          ????????for?(Receipt?receipt?:?receiptList)?{
          ????????????//獲取并設置策略
          ????????????IReceiptHandleStrategy?receiptHandleStrategy?=?ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());
          ????????????receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy);
          ????????????//執(zhí)行策略
          ????????????receiptStrategyContext.handleReceipt(receipt);
          ????????}
          ????}
          }

          解析報文MT2101:我是MT2101回執(zhí)報文喔
          解析報文MT8104:我是MT8104回執(zhí)報文喔

          由于我們的目的是消除if-else,那么這里需要將ReceiptHandleStrategyFactory策略工廠進行改造下,采用字典的方式存放我的策略,而Map具備key-value結構,采用Map是個不錯選擇。

          稍微改造下,代碼如下

          /**
          ?*?@Description:?策略工廠
          ?*?@Auther:?wuzhazha
          ?*/

          public?class?ReceiptHandleStrategyFactory?{

          ????private?static?Map?receiptHandleStrategyMap;

          ????private?ReceiptHandleStrategyFactory(){
          ????????this.receiptHandleStrategyMap?=?new?HashMap<>();
          ????????this.receiptHandleStrategyMap.put("MT2101",new?Mt2101ReceiptHandleStrategy());
          ????????this.receiptHandleStrategyMap.put("MT8104",new?Mt8104ReceiptHandleStrategy());
          ????}

          ????public?static?IReceiptHandleStrategy?getReceiptHandleStrategy(String?receiptType){
          ????????return?receiptHandleStrategyMap.get(receiptType);
          ????}
          }

          經(jīng)過對策略模式+簡單工廠方案的改造,我們已經(jīng)消除了if-else的結構,每當新來了一種回執(zhí),只需要添加新的回執(zhí)處理策略,并修改ReceiptHandleStrategyFactory中的Map集合。

          如果要使得程序符合開閉原則,則需要調整ReceiptHandleStrategyFactory中處理策略的獲取方式,通過反射的方式,獲取指定包下的所有IReceiptHandleStrategy實現(xiàn)類,然后放到字典Map中去。系統(tǒng)學習設計模式:設計模式內容聚合

          責任鏈模式

          責任鏈模式是一種對象的行為模式。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。

          發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織和分配責任

          回執(zhí)處理者接口

          /**
          ?*?@Description:?抽象回執(zhí)處理者接口
          ?*?@Auther:?wuzhazha
          ?*/

          public?interface?IReceiptHandler?{

          ????void?handleReceipt(Receipt?receipt,IReceiptHandleChain?handleChain);

          }

          責任鏈接口

          /**
          ?*?@Description:?責任鏈接口
          ?*?@Auther:?wuzhazha
          ?*/

          public?interface?IReceiptHandleChain?{

          ????void?handleReceipt(Receipt?receipt);
          }

          責任鏈接口實現(xiàn)類

          /**
          ?*?@Description:?責任鏈實現(xiàn)類
          ?*?@Auther:?wuzhazha
          ?*/

          public?class?ReceiptHandleChain?implements?IReceiptHandleChain?{
          ????//記錄當前處理者位置
          ????private?int?index?=?0;
          ????//處理者集合
          ????private?static?List?receiptHandlerList;

          ????static?{
          ????????//從容器中獲取處理器對象
          ????????receiptHandlerList?=?ReceiptHandlerContainer.getReceiptHandlerList();
          ????}

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt)?{
          ????????if?(receiptHandlerList?!=null?&&?receiptHandlerList.size()?>?0)?{
          ????????????if?(index?!=?receiptHandlerList.size())?{
          ????????????????IReceiptHandler?receiptHandler?=?receiptHandlerList.get(index++);
          ????????????????receiptHandler.handleReceipt(receipt,this);
          ????????????}
          ????????}
          ????}
          }

          具體回執(zhí)處理者

          public?class?Mt2101ReceiptHandler?implements?IReceiptHandler?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt,?IReceiptHandleChain?handleChain)?{
          ????????if?(StringUtils.equals("MT2101",receipt.getType()))?{
          ????????????System.out.println("解析報文MT2101:"?+?receipt.getMessage());
          ????????}?
          ????????//處理不了該回執(zhí)就往下傳遞
          ????????else?{??????????
          ????????????handleChain.handleReceipt(receipt);
          ????????}
          ????}
          }

          public?class?Mt8104ReceiptHandler?implements?IReceiptHandler?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt,?IReceiptHandleChain?handleChain)?{
          ????????if?(StringUtils.equals("MT8104",receipt.getType()))?{
          ????????????System.out.println("解析報文MT8104:"?+?receipt.getMessage());
          ????????}
          ????????//處理不了該回執(zhí)就往下傳遞
          ????????else?{
          ????????????handleChain.handleReceipt(receipt);
          ????????}
          ????}
          }

          責任鏈處理者容器(如果采用spring,則可以通過依賴注入的方式獲取到IReceiptHandler的子類對象)

          /**
          ?*?@Description:?處理者容器
          ?*?@Auther:?wuzhazha
          ?*/

          public?class?ReceiptHandlerContainer?{

          ????private?ReceiptHandlerContainer(){}

          ????public?static?List?getReceiptHandlerList(){
          ????????List?receiptHandlerList?=?new?ArrayList<>();
          ????????receiptHandlerList.add(new?Mt2101ReceiptHandler());
          ????????receiptHandlerList.add(new?Mt8104ReceiptHandler());
          ????????return?receiptHandlerList;
          ????}

          }

          客戶端

          public?class?Client?{

          ????public?static?void?main(String[]?args)?{
          ????????//模擬回執(zhí)
          ????????List?receiptList?=?ReceiptBuilder.generateReceiptList();
          ????????for?(Receipt?receipt?:?receiptList)?{
          ????????????//回執(zhí)處理鏈對象
          ????????????ReceiptHandleChain?receiptHandleChain?=?new?ReceiptHandleChain();
          ????????????receiptHandleChain.handleReceipt(receipt);
          ????????}
          ????}
          }

          解析報文MT2101:我是MT2101回執(zhí)報文喔
          解析報文MT8104:我是MT8104回執(zhí)報文喔

          通過責任鏈的處理方式,if-else結構也被我們消除了,每當新來了一種回執(zhí),只需要添加IReceiptHandler實現(xiàn)類并修改ReceiptHandlerContainer處理者容器即可,如果要使得程序符合開閉原則,則需要調整ReceiptHandlerContainer中處理者的獲取方式,通過反射的方式,獲取指定包下的所有IReceiptHandler實現(xiàn)類。Java知音公眾號內回復“后端面試”,送你一份面試寶典

          這里使用到了一個反射工具類,用于獲取指定接口的所有實現(xiàn)類

          /**
          ?*?@Description:?反射工具類
          ?*?@Auther:?wuzhazha
          ?*/

          public?class?ReflectionUtil?{

          ????/**
          ?????*?定義類集合(用于存放所有加載的類)
          ?????*/

          ????private?static?final?Set>?CLASS_SET;

          ????static?{
          ????????//指定加載包路徑
          ????????CLASS_SET?=?getClassSet("com.yaolong");
          ????}

          ????/**
          ?????*?獲取類加載器
          ?????*?@return
          ?????*/

          ????public?static?ClassLoader?getClassLoader(){
          ????????return?Thread.currentThread().getContextClassLoader();
          ????}

          ????/**
          ?????*?加載類
          ?????*?@param?className?類全限定名稱
          ?????*?@param?isInitialized?是否在加載完成后執(zhí)行靜態(tài)代碼塊
          ?????*?@return
          ?????*/

          ????public?static?Class?loadClass(String?className,boolean?isInitialized)?{
          ????????Class?cls;
          ????????try?{
          ????????????cls?=?Class.forName(className,isInitialized,getClassLoader());
          ????????}?catch?(ClassNotFoundException?e)?{
          ????????????throw?new?RuntimeException(e);
          ????????}
          ????????return?cls;
          ????}

          ????public?static?Class?loadClass(String?className)?{
          ????????return?loadClass(className,true);
          ????}

          ????/**
          ?????*?獲取指定包下所有類
          ?????*?@param?packageName
          ?????*?@return
          ?????*/

          ????public?static?Set>?getClassSet(String?packageName)?{
          ????????Set>?classSet?=?new?HashSet<>();
          ????????try?{
          ????????????Enumeration?urls?=?getClassLoader().getResources(packageName.replace(".","/"));
          ????????????while?(urls.hasMoreElements())?{
          ????????????????URL?url?=?urls.nextElement();
          ????????????????if?(url?!=?null)?{
          ????????????????????String?protocol?=?url.getProtocol();
          ????????????????????if?(protocol.equals("file"))?{
          ????????????????????????String?packagePath?=?url.getPath().replace("%20","");
          ????????????????????????addClass(classSet,packagePath,packageName);
          ????????????????????}?else?if?(protocol.equals("jar"))?{
          ????????????????????????JarURLConnection?jarURLConnection?=?(JarURLConnection)?url.openConnection();
          ????????????????????????if?(jarURLConnection?!=?null)?{
          ????????????????????????????JarFile?jarFile?=?jarURLConnection.getJarFile();
          ????????????????????????????if?(jarFile?!=?null)?{
          ????????????????????????????????Enumeration?jarEntries?=?jarFile.entries();
          ????????????????????????????????while?(jarEntries.hasMoreElements())?{
          ????????????????????????????????????JarEntry?jarEntry?=?jarEntries.nextElement();
          ????????????????????????????????????String?jarEntryName?=?jarEntry.getName();
          ????????????????????????????????????if?(jarEntryName.endsWith(".class"))?{
          ????????????????????????????????????????String?className?=?jarEntryName.substring(0,?jarEntryName.lastIndexOf(".")).replaceAll("/",?".");
          ????????????????????????????????????????doAddClass(classSet,className);
          ????????????????????????????????????}
          ????????????????????????????????}
          ????????????????????????????}
          ????????????????????????}
          ????????????????????}
          ????????????????}
          ????????????}


          ????????}?catch?(IOException?e)?{
          ????????????throw?new?RuntimeException(e);
          ????????}
          ????????return?classSet;
          ????}

          ????private?static?void?doAddClass(Set>?classSet,?String?className)?{
          ????????Class?cls?=?loadClass(className,false);
          ????????classSet.add(cls);
          ????}

          ????private?static?void?addClass(Set>?classSet,?String?packagePath,?String?packageName)?{
          ????????final?File[]?files?=?new?File(packagePath).listFiles(new?FileFilter()?{
          ????????????@Override
          ????????????public?boolean?accept(File?file)?{
          ????????????????return?(file.isFile()?&&?file.getName().endsWith(".class"))?||?file.isDirectory();
          ????????????}
          ????????});
          ????????for?(File?file?:?files)?{
          ????????????String?fileName?=?file.getName();
          ????????????if?(file.isFile())?{
          ????????????????String?className?=?fileName.substring(0,?fileName.lastIndexOf("."));
          ????????????????if?(StringUtils.isNotEmpty(packageName))?{
          ????????????????????className?=?packageName?+?"."?+?className;
          ????????????????}
          ????????????????doAddClass(classSet,className);
          ????????????}?else?{
          ????????????????String?subPackagePath?=?fileName;
          ????????????????if?(StringUtils.isNotEmpty(packagePath))?{
          ????????????????????subPackagePath?=?packagePath?+?"/"?+?subPackagePath;
          ????????????????}
          ????????????????String?subPackageName?=?fileName;
          ????????????????if?(StringUtils.isNotEmpty(packageName))?{
          ????????????????????subPackageName?=?packageName?+?"."?+?subPackageName;
          ????????????????}
          ????????????????addClass(classSet,subPackagePath,subPackageName);
          ????????????}
          ????????}
          ????}


          ????public?static?Set>?getClassSet()?{
          ????????return?CLASS_SET;
          ????}

          ????/**
          ?????*?獲取應用包名下某父類(或接口)的所有子類(或實現(xiàn)類)
          ?????*?@param?superClass
          ?????*?@return
          ?????*/

          ????public?static?Set>?getClassSetBySuper(Class?superClass)?{
          ????????Set>?classSet?=?new?HashSet<>();
          ????????for?(Class?cls?:?CLASS_SET)?{
          ????????????if?(superClass.isAssignableFrom(cls)?&&?!superClass.equals(cls))?{
          ????????????????classSet.add(cls);
          ????????????}
          ????????}
          ????????return?classSet;
          ????}

          ????/**
          ?????*?獲取應用包名下帶有某注解的類
          ?????*?@param?annotationClass
          ?????*?@return
          ?????*/

          ????public?static?Set>?getClassSetByAnnotation(Class?annotationClass)?{
          ????????Set>?classSet?=?new?HashSet<>();
          ????????for?(Class?cls?:?CLASS_SET)?{
          ????????????if?(cls.isAnnotationPresent(annotationClass))?{
          ????????????????classSet.add(cls);
          ????????????}
          ????????}
          ????????return?classSet;
          ????}

          }

          接下來改造ReceiptHandlerContainer

          public?class?ReceiptHandlerContainer?{

          ????private?ReceiptHandlerContainer(){}

          ????public?static?List?getReceiptHandlerList(){
          ????????List?receiptHandlerList?=?new?ArrayList<>();
          ????????//獲取IReceiptHandler接口的實現(xiàn)類
          ????????Set>?classList?=?ReflectionUtil.getClassSetBySuper(IReceiptHandler.class);
          ????????if?(classList?!=?null?&&?classList.size()?>?0)?{
          ????????????for?(Class?clazz?:?classList)?{
          ????????????????try?{
          ????????????????????receiptHandlerList.add((IReceiptHandler)clazz.newInstance());
          ????????????????}?catch?(?Exception?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????}
          ????????return?receiptHandlerList;
          ????}

          }

          至此,該方案完美符合了開閉原則,如果新增一個回執(zhí)類型,只需要添加一個新的回執(zhí)處理器即可,無需做其它改動。如新加了MT6666的回執(zhí),代碼如下

          public?class?Mt6666ReceiptHandler?implements?IReceiptHandler?{

          ????@Override
          ????public?void?handleReceipt(Receipt?receipt,?IReceiptHandleChain?handleChain)?{
          ????????if?(StringUtils.equals("MT6666",receipt.getType()))?{
          ????????????System.out.println("解析報文MT6666:"?+?receipt.getMessage());
          ????????}
          ????????//處理不了該回執(zhí)就往下傳遞
          ????????else?{
          ????????????handleChain.handleReceipt(receipt);
          ????????}
          ????}
          }

          策略模式+注解

          此方案其實和上述沒有太大異同,為了能符合開閉原則,通過自定義注解的方式,標記處理者類,然后反射獲取到該類集合,放到Map容器中,這里不再贅述

          小結

          if-else或switch case 這種分支判斷的方式對于分支邏輯不多的簡單業(yè)務,還是直觀高效的。對于業(yè)務復雜,分支邏輯多,采用適當?shù)哪J郊记桑瑫尨a更加清晰,容易維護,但同時類或方法數(shù)量也是倍增的。我們需要對業(yè)務做好充分分析,避免一上來就設計模式,避免過度設計!

          —??—

          點這里??關注我,記得標星呀~


          前線推出學習交流一定要備注:研究/工作方向+地點+學校/公司+昵稱(如JAVA+上海

          掃碼加小編微信,進群和大佬們零距離



          END



          好文點個在看吧!
          瀏覽 32
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  巨乳全裸家证父 | 97国产超碰在线观看 | 鲁鲁日韩成人免费视频 | 午夜成人激情视频 | 免费一级毛片 |