2025-04-30

我在程序裡也碰到過一次這樣的狀況,非靜態內部類可以直接調用外部類實例的成員變量,但如何引用外部類的實例本身卻成瞭一個問題,下面的這個方法正好解決瞭這個問題。見下面那句紅色的代碼。

看一段代碼
import java.util.LinkedList;
import java.util.List;
public class OuterClass
{
 private List listeners = new LinkedList();
 public void addListeners(IListener listener)
 {
  this.listeners.add(listener);
 }
 private OuterClass outer = this;  (1)
 private class InnterClass
 {
  public void publish()
  {
   //將事件發佈出去 (2)
   for(int i=0;i < listeners.size();i )
   {
    IListener listener = (IListener) listeners.get(i);
    listener.receiveEvent(outer);
   }
  }
 }

 public void execute()
 {
  InnterClass in = new InnterClass(); (3)
  in.publish();
 }
}

public interface IListener
{
public void receiveEvent(OuterClass obj);
}

你可能覺得這個例子很別扭,在哪裡讓你覺得難受呢?其實問題的關鍵就在於接口IListener的定義,這裡需要給receiveEvent方法傳遞的參數是外部對象!(別激動,下面我會說明需要傳遞的一個場景)

場景

在一個GUI系統中,我們要在畫板WorkSpace(WorkSpace實現瞭IListener接口)上產生一顆樹,但樹中的每個節點的產生(繪圖)是我們不知道的算法,系統隻為我們提供瞭一些繪圖的接口,並返回元素的句柄!看來我們需要”包裝”一下這個繪圖的句柄Brush(其實我把它叫做筆刷,因為它隻知道如何”刷”出圖像來,就這點本事!)並對外提供節點Node這樣一個通用的類。

此時Node與Brush的關系就很微妙瞭,不過我們可以拋開這些外表,看到Node與Brush其實就是外部類與內部類的關系!-第一步完成瞭:確定瞭兩者的關系

然而,事情沒有這麼簡單,Node類必須處理一些事件,而這些事件理所當然隻有Brush能夠看懂,而Node根本不知道這樣的事件處理過程,現在有兩個辦法:辦法一,讓Node實現Brush所有的事件;辦法二,把Brush返回回去,讓它來處理自己的事件,看來辦法二是個好主意,因為我可以不關心事件的種類!-第二步完成瞭:確定瞭事件處理的責任

還沒完呢,你肯定不希望畫板WorkSpace面對的是繪圖的句柄Brush這樣的對象,相反你隻希望WokSpace隻知道Node的存在!IListener接口中receiveEvent方法的參數定義為OuterClass 就由此而來!-第三步完成:接口的定義

public interface IListener
{
public void receiveEvent(OuterClass obj);
}

既然說清楚瞭這個問題(應該比較清楚瞭吧?)那改如何實現這樣一個蹩腳而有無可奈何的設計呢?讓我們回憶一下內部類,內部類擁有訪問外部類的方法與屬性的權限
 private OuterClass outer = this;  - 這個對外部類的引用就是為內部類的訪問準備的
 private class InnterClass
 {
  public void publish()
  {
   //將事件發佈出去
   for(int i=0;i < listeners.size();i )
   {
    IListener listener = (IListener) listeners.get(i);
    listener.receiveEvent(outer);  - 這裡不可以返回this,因為this代表的是內部類自己
   }
  }

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *