<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問 http://qaseven.github.io/

    跟屌絲大哥學(xué)習(xí)設(shè)計(jì)模式---觀察者模式

    Java 觀察者模式的淺析

    簡(jiǎn)單地說,觀察者模式定義了一個(gè)一對(duì)多的依賴關(guān)系,讓一個(gè)或多個(gè)觀察者對(duì)象監(jiān)察一個(gè)主題對(duì)象。這樣一個(gè)主題對(duì)象在狀態(tài)上的變化能夠通知所有的依賴于此對(duì)象的那些觀察者對(duì)象,使這些觀察者對(duì)象能夠自動(dòng)更新。
     觀察者模式的結(jié)構(gòu)

      觀察者(Observer)模式是對(duì)象的行為型模式,又叫做發(fā)表-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-收聽者(Source/Listener)模式或從屬者(Dependents)模式。

     本模式的類圖結(jié)構(gòu)如下:


    圖1、觀察者模式的靜態(tài)結(jié)構(gòu)可從類圖中看清楚。

      在觀察者模式里有如下的角色:
     . 抽象主題(Subject)角色:主題角色把所有的觀察者對(duì)象的引用保存在一個(gè)列表里;每個(gè)主題都可以有任何數(shù)量的觀察者。主題提供一個(gè)接口可以加上或撤銷觀察者對(duì)象;主題角色又叫做抽象被觀察者(Observable)角色; 

    圖2、抽象主題角色,有時(shí)又叫做抽象被觀察者角色,可以用一個(gè)抽象類或者一個(gè)接口實(shí)現(xiàn);在具體的情況下也不排除使用具體類實(shí)現(xiàn)。

      . 抽象觀察者(Observer)角色:為所有的具體觀察者定義一個(gè)接口,在得到通知時(shí)更新自己; 



    圖3、抽象觀察者角色,可以用一個(gè)抽象類或者一個(gè)接口實(shí)現(xiàn);在具體的情況下也不排除使用具體類實(shí)現(xiàn)。

      . 具體主題(ConcreteSubject)角色:保存對(duì)具體觀察者對(duì)象有用的內(nèi)部狀態(tài);在這種內(nèi)部狀態(tài)改變時(shí)給其觀察者發(fā)出一個(gè)通知;具體主題角色又叫作具體被觀察者角色;


    圖4、具體主題角色,通常用一個(gè)具體子類實(shí)現(xiàn)。

    具體觀察者(ConcreteObserver)角色:保存一個(gè)指向具體主題對(duì)象的引用;和一個(gè)與主題的狀態(tài)相符的狀態(tài)。具體觀察者角色實(shí)現(xiàn)抽象觀察者角色所要求的更新自己的接口,以便使本身的狀態(tài)與主題的狀態(tài)自恰。 


    圖5、具體觀察者角色,通常用一個(gè)具體子類實(shí)現(xiàn)。

    下面給出一個(gè)示意性實(shí)現(xiàn)的Java代碼。首先在這個(gè)示意性的實(shí)現(xiàn)里,用一個(gè)Java接口實(shí)現(xiàn)抽象主題角色,這就是下面的Subject接口:


    public interface Subject
    {
    public void attach(Observer observer);

    public void detach(Observer observer);

    void notifyObservers();
    }
    代碼清單1、Subject接口的源代碼。 

      這個(gè)抽象主題接口規(guī)定出三個(gè)子類必須實(shí)現(xiàn)的操作,即 attach() 用來增加一個(gè)觀察者對(duì)象;detach() 用來刪除一個(gè)觀察者對(duì)象;和notifyObservers() 用來通知各個(gè)觀察者刷新它們自己。抽象主題角色實(shí)際上要求子類保持一個(gè)以所有的觀察者對(duì)象為元素的列表。

      具體主題則是實(shí)現(xiàn)了抽象主題Subject接口的一個(gè)具體類,它給出了以上的三個(gè)操作的具體實(shí)現(xiàn)。從下面的源代碼可以看出,這里給出的Java實(shí)現(xiàn)使用了一個(gè)Java向量來保存所有的觀察者對(duì)象,而 attach() 和 detach() 操作則是對(duì)此向量的元素增減操作。


    import java.util.Vector;
    import java.util.Enumeration;

    public class ConcreteSubject implements Subject
    {
    public void attach(Observer observer)
    {
    observersVector.addElement(observer);
    }

    public void detach(Observer observer)
    {
    observersVector.removeElement(observer);
    }

    public void notifyObservers()
    {
    Enumeration enumeration = observers();
    while (enumeration.hasMoreElements())
    {
    ((Observer)enumeration.nextElement()).update();
    }
    }

    public Enumeration observers()
    {
    return ((Vector) observersVector.clone()).elements();
    }
    private Vector observersVector = new java.util.Vector();
    }
    代碼清單2、ConcreteSubject類的源代碼。 
      抽象觀察者角色的實(shí)現(xiàn)實(shí)際上是最為簡(jiǎn)單的一個(gè),它是一個(gè)Java接口,只聲明了一個(gè)方法,即update()。這個(gè)方法被子類實(shí)現(xiàn)后,一被調(diào)用便刷新自己。

    public interface Observer
    {
    void update();
    }
    代碼清單3、Observer接口的源代碼。 

      具體觀察者角色的實(shí)現(xiàn)其實(shí)只涉及update()方法的實(shí)現(xiàn)。這個(gè)方法怎么實(shí)現(xiàn)與應(yīng)用密切相關(guān),因此本類只給出一個(gè)框架。
    public class ConcreteObserver implements Observer
    {
    public void update()
    {
    // Write your code here
    }
    }
    代碼清單4、ConcreteObserver類的源代碼。 

      雖然觀察者模式的實(shí)現(xiàn)方法可以有設(shè)計(jì)師自己確定,但是因?yàn)閺腁WT1.1開始視窗系統(tǒng)的事件模型采用觀察者模式,因此觀察者模式在Java語言里的地位較為重要。正因?yàn)檫@個(gè)原因,Java語言給出了它自己對(duì)觀察者模式的支持。因此,本文建議讀者在自己的系統(tǒng)中應(yīng)用觀察者模式時(shí),不妨利用Java語言所提供的支持。
      Java語言提供的對(duì)觀察者模式的支持

      在Java語言的java.util庫里面,提供了一個(gè)Observable類以及一個(gè)Observer接口,構(gòu)成Java語言對(duì)觀察者模式的支持。

      Observer接口

      這個(gè)接口只定義了一個(gè)方法,update()。當(dāng)被觀察者對(duì)象的狀態(tài)發(fā)生變化時(shí),這個(gè)方法就會(huì)被調(diào)用。這個(gè)方法的實(shí)現(xiàn)應(yīng)當(dāng)調(diào)用每一個(gè)被觀察者對(duì)象的notifyObservers()方法,從而通知所有的觀察對(duì)象。


    圖6、java.util提供的Observer接口的類圖。


    package java.util;

    public interface Observer
    {
    /**
    * 當(dāng)被觀察的對(duì)象發(fā)生變化時(shí),這個(gè)方法會(huì)被調(diào)用。
    */
    void update(Observable o, Object arg);
    }
    代碼清單5、java.util.Observer接口的源代碼。 

      Observable類

      被觀察者類都是java.util.Observable類的子類。java.util.Observable提供公開的方法支持觀察者對(duì)象,這些方法中有兩個(gè)對(duì)Observable的子類非常重要:一個(gè)是setChanged(),另一個(gè)是notifyObservers()。第一個(gè)方法setChanged()被調(diào)用之后會(huì)設(shè)置一個(gè)內(nèi)部標(biāo)記變量,代表被觀察者對(duì)象的狀態(tài)發(fā)生了變化。第二個(gè)是notifyObservers(),這個(gè)方法被調(diào)用時(shí),會(huì)調(diào)用所有登記過的觀察者對(duì)象的update()方法,使這些觀察者對(duì)象可以更新自己。

      java.util.Observable類還有其它的一些重要的方法。比如,觀察者對(duì)象可以調(diào)用java.util.Observable類的addObserver()方法,將對(duì)象一個(gè)一個(gè)加入到一個(gè)列表上。當(dāng)有變化時(shí),這個(gè)列表可以告訴notifyObservers()方法那些觀察者對(duì)象需要通知。由于這個(gè)列表是私有的,因此java.util.Observable的子對(duì)象并不知道觀察者對(duì)象一直在觀察著它們。


    圖7、Java語言提供的被觀察者的類圖。

      被觀察者類Observable的源代碼:

    package java.util;
    public class Observable
    {
    private boolean changed = false;
    private Vector obs;

    /** 用0個(gè)觀察者構(gòu)造一個(gè)被觀察者。**/

    public Observable()
    {
    obs = new Vector();
    }


    /**
    * 將一個(gè)觀察者加到觀察者列表上面。
    */

    public synchronized void addObserver(Observer o)
    {
    if (!obs.contains(o))
    {
    obs.addElement(o);
    }

    }


    /**
    * 將一個(gè)觀察者對(duì)象從觀察者列表上刪除。
    */

    public synchronized void deleteObserver(Observer o)
    {
    obs.removeElement(o);
    }


    /**
    * 相當(dāng)于 notifyObservers(null)
    */

    public void notifyObservers()
    {
    notifyObservers(null);
    }


    /**
    * 如果本對(duì)象有變化(那時(shí)hasChanged 方法會(huì)返回true)
    * 調(diào)用本方法通知所有登記在案的觀察者,即調(diào)用它們的update()方法,
    * 傳入this和arg作為參量。
    */

    public void notifyObservers(Object arg)
    {
    /**
    * 臨時(shí)存放當(dāng)前的觀察者的狀態(tài)。參見備忘錄模式。
    */

    Object[] arrLocal;

    synchronized (this)
    {
    if (!changed) return;
    arrLocal = obs.toArray();
    clearChanged();
    }


    for (int i = arrLocal.length-1; i>=0; i--)
    ((Observer)arrLocal[i]).update(this, arg);
    }


    /**
    * 將觀察者列表清空
    */

    public synchronized void deleteObservers()
    {
    obs.removeAllElements();
    }


    /**
    * 將“已變化”設(shè)為true
    */

    protected synchronized void setChanged()
    {
    changed = true;
    }


    /**
    * 將“已變化”重置為false
    */

    protected synchronized void clearChanged()
    {
    changed = false;
    }


    /**
    * 探測(cè)本對(duì)象是否已變化
    */

    public synchronized boolean hasChanged()
    {
    return changed;
    }


    /**
    * 返還被觀察對(duì)象(即此對(duì)象)的觀察者總數(shù)。
    */

    public synchronized int countObservers()
    {
    return obs.size();
    }

    }


    代碼清單6、java.util.Observer接口的源代碼。 

      這個(gè)Observable類代表一個(gè)被觀察者對(duì)象。一個(gè)被觀察者對(duì)象可以有數(shù)個(gè)觀察者對(duì)象,一個(gè)觀察者可以是一個(gè)實(shí)現(xiàn)Observer接口的對(duì)象。在被觀察者對(duì)象發(fā)生變化時(shí),它會(huì)調(diào)用Observable的notifyObservers方法,此方法調(diào)用所有的具體觀察者的update()方法,從而使所有的觀察者都被通知更新自己。見下面的類圖:


    圖8、使用Java語言提供的對(duì)觀察者模式的支持。

      發(fā)通知的次序在這里沒有指明。Observerable類所提供的缺省實(shí)現(xiàn)會(huì)按照Observers對(duì)象被登記的次序通知它們,但是Observerable類的子類可以改掉這一次序。子類并可以在單獨(dú)的線程里通知觀察者對(duì)象;或者在一個(gè)公用的線程里按照次序執(zhí)行。 

      當(dāng)一個(gè)可觀察者對(duì)象剛剛創(chuàng)立時(shí),它的觀察者集合是空的。兩個(gè)觀察者對(duì)象在它們的equals()方法返回true時(shí),被認(rèn)為是兩個(gè)相等的對(duì)象。 
      怎樣使用Java對(duì)觀察者模式的支持

      為了說明怎樣使用Java所提供的對(duì)觀察者模式的支持,本節(jié)給出一個(gè)非常簡(jiǎn)單的例子。在這個(gè)例子里,被觀察對(duì)象叫做Watched,也就是被監(jiān)視者;而觀察者對(duì)象叫做Watcher。Watched對(duì)象繼承自java.util.Obsevable類;而Watcher對(duì)象實(shí)現(xiàn)了java.util.Observer接口。另外有一個(gè)對(duì)象Tester,扮演客戶端的角色。 

      這個(gè)簡(jiǎn)單的系統(tǒng)的結(jié)構(gòu)如下圖所示。 


    圖9、一個(gè)使用Observer接口和Observable類的例子。

      在客戶端改變Watched對(duì)象的內(nèi)部狀態(tài)時(shí),Watched就會(huì)通知Watcher采取必要的行動(dòng)。 


    package com.javapatterns.observer.watching;

    import java.util.Observer;

    public class Tester
    {
    static private Watched watched;
    static private Observer watcher;

    public static void main(String[] args)
    {
    watched = new Watched();

    watcher = new Watcher(watched);

    watched.changeData("In C, we create bugs.");
    watched.changeData("In Java, we inherit bugs.");
    watched.changeData("In Java, we inherit bugs.");
    watched.changeData("In Visual Basic, we visualize bugs."); 
    }

    }


      代碼清單7、Tester類的源代碼。 


     代碼清單7、Tester類的源代碼。 


    package com.javapatterns.observer.watching;

    import java.util.Observable;

    public class Watched extends Observable
    {
    private String data = "";

    public String retrieveData()
    {
    return data;
    }


    public void changeData(String data)
    {
    if ( !this.data.equals( data) )
    {
    this.data = data;
    setChanged();
    }


    notifyObservers();
    }

    }


    代碼清單9、Watcher類的源代碼。 

      可以看出,雖然客戶端將Watched對(duì)象的內(nèi)部狀態(tài)賦值了四次,但是值的改變只有三次:

    watched.changeData("In C, we create bugs.");
    watched.changeData("In Java, we inherit bugs.");
    watched.changeData("In Java, we inherit bugs.");
    watched.changeData("In Visual Basic, we visualize bugs."); 

      代碼清單10、被觀察者的內(nèi)部狀態(tài)發(fā)生了改變。 

      對(duì)應(yīng)地,Watcher對(duì)象匯報(bào)了三次改變,下面就是運(yùn)行時(shí)間程序打印出的信息:

    Data has been changed to: 'In C, we create bugs.'

    Data has been changed to: 'In Java, we inherit bugs.'

    Data has been changed to: 'In Visual Basic, we visualize bugs.'

      代碼清單11、運(yùn)行的結(jié)果。 

     菩薩的守瓶龜

      想當(dāng)年齊天大圣為解救師傅唐僧,前往南海普陀山請(qǐng)菩薩降伏妖怪紅孩兒:“菩薩聽說...恨了一聲,將手中寶珠凈瓶往海心里撲的一摜...只見那海當(dāng)中,翻波跳浪,鉆出個(gè)瓶來,原來是一個(gè)怪物馱著出來...要知此怪名和姓,興風(fēng)作浪惡烏龜。” 

      使用面向?qū)ο蟮恼Z言描述,烏龜便是一個(gè)觀察者對(duì)象,它觀察的主題是菩薩。一旦菩薩將凈瓶摜到海里,就象征著菩薩作為主題調(diào)用了notifyObservers()方法。在西游記中,觀察者對(duì)象有兩個(gè),一個(gè)是烏龜,另一個(gè)是悟空。悟空的反應(yīng)在這里暫時(shí)不考慮,而烏龜?shù)姆磻?yīng)便是將瓶子馱回海岸。 


    圖10、菩薩和菩薩的守瓶烏龜。
    Java中的DEM事件機(jī)制

      AWT中的DEM機(jī)制

      責(zé)任鏈模式一章中曾談到,AWT1.0的事件處理的模型是基于責(zé)任鏈的。這種模型不適用于復(fù)雜的系統(tǒng),因此在AWT1.1版本及以后的各個(gè)版本中,事件處理模型均為基于觀察者模式的委派事件模型(Delegation Event Model或DEM)。 

      在DEM模型里面,主題(Subject)角色負(fù)責(zé)發(fā)布(publish)事件,而觀察者角色向特定的主題訂閱(subscribe)它所感興趣的事件。當(dāng)一個(gè)具體主題產(chǎn)生一個(gè)事件時(shí),它就會(huì)通知所有感興趣的訂閱者。 

      使用這種發(fā)布-訂閱機(jī)制的基本設(shè)計(jì)目標(biāo),是提供一種將發(fā)布者與訂閱者松散地耦合在一起的聯(lián)系形式,以及一種能夠動(dòng)態(tài)地登記、取消向一個(gè)發(fā)布者的訂閱請(qǐng)求的辦法。顯然,實(shí)現(xiàn)這一構(gòu)思的技巧,是設(shè)計(jì)抽象接口,并把抽象層和具體層分開。這在觀察者模式里可以清楚地看到。 

      使用DEM的用詞,發(fā)布者叫做事件源(event source),而訂閱者叫做事件聆聽者(event listener)。在Java里面,事件由類代表,事件的發(fā)布是通過同步地調(diào)用成員方法做到的。 

      Servlet技術(shù)中的的DEM機(jī)制

      AWT中所使用的DEM事件模型實(shí)際上被應(yīng)用到了所有的Java事件機(jī)制上。Servlet技術(shù)中的事件處理機(jī)制同樣也是使用的DEM模型。 

      SAX2技術(shù)中的DEM機(jī)制

      DEM事件模型也被應(yīng)用到了SAX2的事件處理機(jī)制上。 

      觀察者模式的效果

      觀察者模式的效果有以下的優(yōu)點(diǎn): 

      第一、觀察者模式在被觀察者和觀察者之間建立一個(gè)抽象的耦合。被觀察者角色所知道的只是一個(gè)具體觀察者列表,每一個(gè)具體觀察者都符合一個(gè)抽象觀察者的接口。被觀察者并不認(rèn)識(shí)任何一個(gè)具體觀察者,它只知道它們都有一個(gè)共同的接口。 

      由于被觀察者和觀察者沒有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。如果被觀察者和觀察者都被扔到一起,那么這個(gè)對(duì)象必然跨越抽象化和具體化層次。 

      第二、觀察者模式支持廣播通訊。被觀察者會(huì)向所有的登記過的觀察者發(fā)出通知, 

      觀察者模式有下面的缺點(diǎn): 

      第一、如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。 

      第二、如果在被觀察者之間有循環(huán)依賴的話,被觀察者會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,導(dǎo)致系統(tǒng)崩潰。在使用觀察者模式是要特別注意這一點(diǎn)。 

      第三、如果對(duì)觀察者的通知是通過另外的線程進(jìn)行異步投遞的話,系統(tǒng)必須保證投遞是以自恰的方式進(jìn)行的。 

      第四、雖然觀察者模式可以隨時(shí)使觀察者知道所觀察的對(duì)象發(fā)生了變化,但是觀察者模式?jīng)]有相應(yīng)的機(jī)制使觀察者知道所觀察的對(duì)象是怎么發(fā)生變化的。 

      觀察者模式與其它模式的關(guān)系

      觀察者模式使用了備忘錄模式(Memento Pattern)暫時(shí)將觀察者對(duì)象存儲(chǔ)在被觀察者對(duì)象里面。

      問答題

      第一題、我和妹妹跟媽媽說:“媽媽,我和妹妹在院子里玩;飯做好了叫我們一聲。”請(qǐng)問這是什么模式?能否給出類圖說明?

      問答題答案

      第一題答案、這是觀察者模式。我和妹妹讓媽媽告訴我們飯做好了,這樣我們就可以來吃飯了。換用較為技術(shù)化的語言來說,當(dāng)系統(tǒng)的主題(飯)發(fā)生變化時(shí),就告訴系統(tǒng)的其它部份(觀察者們,也就是媽媽、我和妹妹),使其可以調(diào)整內(nèi)部狀態(tài)(有開始吃飯的準(zhǔn)備),并采取相應(yīng)的行動(dòng)(吃飯)。

      系統(tǒng)的類圖說明如下。


    圖11、系統(tǒng)的類圖。


    網(wǎng)上商店中的商品在名稱、價(jià)格發(fā)生變化時(shí),必須自動(dòng)通知會(huì)員,Java的API為我們提供了Observer接口和Observable類來實(shí)現(xiàn)所謂觀察者模式。
    Observable(可觀察者)類允許在自身發(fā)生改變時(shí),通知其它對(duì)象(實(shí)現(xiàn)接口Observer,觀察者)。

    下面是一個(gè)可觀察者(產(chǎn)品類):
    import java.util.*;
    public class product extends Observable{ 
       private String name;////產(chǎn)品名
       private float price;////價(jià)格

       public String getName(){ return name;}
       public void setName(String name){
        this.name=name;
       ////設(shè)置變化點(diǎn) 
        setChanged();
        notifyObservers(name);////通知觀察者

       }   

       public float getPrice(){ return price;}
       public void setPrice(float price){
        this.price=price;
       ////設(shè)置變化點(diǎn)
        setChanged();
        notifyObservers(new Float(price));

       }

       ////以下可以是數(shù)據(jù)庫更新 插入命令.
       public void saveToDb(){
       System.out.println("saveToDb");
        }

    }

    下面是兩個(gè)觀察者:
    import java.util.*;
    public class NameObserver implements Observer{

       private String name=null;
       public void update(Observable obj,Object arg){
         if (arg instanceof String){
          name=(String)arg;
          ////產(chǎn)品名稱改變值在name中
          System.out.println("NameObserver :name changet to "+name);

         }

          }
       }

    import java.util.*;
    public class PriceObserver implements Observer{
       private float price=0;
       public void update(Observable obj,Object arg){
         if (arg instanceof Float){

          price=((Float)arg).floatValue();
      
          System.out.println("PriceObserver :price changet to "+price);

         }


       }

    }
    下面是測(cè)試類:
    public class Test {

       public static void main(String args[]){
        Product product=new Product();
        NameObserver nameobs=new NameObserver();
        PriceObserver priceobs=new PriceObserver();

        ////加入觀察者
        product.addObserver(nameobs);
        product.addObserver(priceobs);

        product.setName("applet");
        product.setPrice(9.22f);

       }
    }

     

    posted on 2012-12-11 11:51 順其自然EVO 閱讀(491) 評(píng)論(0)  編輯  收藏 所屬分類: 設(shè)計(jì)模式學(xué)習(xí)

    <2012年12月>
    2526272829301
    2345678
    9101112131415
    16171819202122
    23242526272829
    303112345

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 亚洲日本在线电影| 老司机亚洲精品影院无码 | 最近中文字幕大全中文字幕免费 | 激情亚洲一区国产精品| 一级毛片免费观看不卡视频| 亚洲精品中文字幕乱码三区| 国产一级高青免费| 亚洲成av人片天堂网| 国产麻豆一精品一AV一免费| 亚洲AV无码乱码国产麻豆| 91在线免费观看| 久久久久久久久亚洲| 亚洲一级毛片免费观看| 亚洲乱码一区av春药高潮| 国产成在线观看免费视频| 亚洲综合精品成人| 亚洲国产小视频精品久久久三级| 一个人晚上在线观看的免费视频| 亚洲无线码在线一区观看| 久久综合国产乱子伦精品免费| 亚洲成AV人片久久| 四虎成人免费网址在线| 黄床大片30分钟免费看| 亚洲无线码在线一区观看| 1000部羞羞禁止免费观看视频| 亚洲国产午夜电影在线入口| 成年人性生活免费视频| 成年大片免费高清在线看黄| 亚洲AV无码专区国产乱码电影| 亚洲成年人免费网站| 日韩欧美亚洲中文乱码| 亚洲色偷拍另类无码专区| 亚洲成人免费网址| 日本中文字幕免费看| 亚洲天堂中文字幕| 无码国模国产在线观看免费| 拍拍拍无挡视频免费观看1000| 亚洲最大黄色网站| 亚洲精品动漫人成3d在线| 91视频免费网址| 小说区亚洲自拍另类|