2011-07-21 53 views
4
  • 類和方法類的情況下,一個很好的做法:

如果我們使用工廠方法,我們將不得不返回創建作爲實現的接口的類型實現。這是使用「默認」 Java訪問隱藏從客戶端

public class Factory { 

    public Product getProduct() { 
    return new ProductA(); 
    } 
} 

public interface Product { 
} 

class ProductA implements Product { 
} 

爲了避免客戶的投退還的產品來具體實現產品{A,B,C ...等},我們有能力:

  1. 將客戶端和工廠代碼分開包裝(比如說com.example.clientcom.example.factory
  2. 聲明混凝土implemantations使用默認( 「包」)的訪問(可見於工廠,而不是客戶端可見)

package com.example.client; 
    ... 
    public class Client { 
     public static void main(String[] args) { 
     Product i = new Factory().getProduct(); 
     ProductA a = (ProductA) i; // the type of ProductA isn't visible. 
     } 
    } 
  • 在方法的情況下:

例如我們需要使用與隱藏方法相同的工廠

public class Factory { 

    public Product getProduct() { 
    return new ProductA(); 
    } 

    Product[] getCreatedProducts() { 
    ... 
    } 
} 

我在這裏看到了兩個問題:

  • 壞包結構:隱藏的類和方法必須是在一個封裝與調用代碼。
  • 錯誤代碼:不那麼直觀和易於理解。將java文件替換爲另一個包很容易。
+0

我還以爲是一樣的'protected',但我不知道。我總是定義一個訪問關鍵字。 –

+0

@Martijn'protected'對包和子類是可訪問的。默認(無關鍵字)可以打包訪問,但不能訪問子類。 – toto2

+0

@Agasteted我認爲你做對了。但我不明白你的「兩個問題」。另外我不太清楚爲什麼你這樣做:爲什麼要隱藏來自客戶端的不同'Product'類型? – toto2

回答

2

「默認」訪問不保證任何東西,因爲任何流氓程序員都可以在你的包中聲明他們的類。另外,無論你的包結構如何,在java中,你幾乎總是可以做一個「實例」檢查,然後向下轉換爲「實例」類型。因此,如果您的目標是防止任何向下滾動,您必須使用private關鍵字。例如,您可以將您Factory內聲明的Product接口private static或匿名內部類的具體實現。事實上,在Bloch的「如何設計一個好的API」文章中,他指出你應該「儘量減少一切的可訪問性」。

這麼說,我覺得你是一個有點偏執這裏。如果有人沮喪,這對你來說真的很重要嗎?您編寫的任何代碼都可能被濫用,當然,如果您包含完善文檔的工廠,那麼您已經提供了有關如何正確使用API​​的明確信息。另外,如果你構建了一個真實的工廠方法,它帶有參數並且有明確的方法名稱,相對於這個不帶任何參數的玩具例子,那麼我認爲你會發現你正在廣播正在創建的公共相關部分無論如何。

2

我真的不明白你爲什麼要把工廠和類分開包。

我通常在同一個包中創建公共接口,公共工廠類和包保護實現。因此,客戶端只能使用工廠創建實例,並且無法下載,因爲具體的類在其他包中不可見。

+0

問題是「默認訪問是否足夠使用」。我認爲這不是,我們必須始終定義訪問關鍵字。我只想知道是否有更好的方法可以避免客戶端從客戶端投射和隱藏方法。 – trupanka

+0

@Aghasted爲什麼你有包訪問問題?這不是真正的「默認」,只是沒有關鍵字需要進行包保護訪問。另外,你唯一的選擇是擁有一個私有工廠的內部類。 – Bringer128

1

在你的情況下,你有客戶知道知道實現類的工廠。如果它們都處於同一個進程中,那麼客戶端和實現類都會加載到同一個進程中,這意味着客戶端可以通過反射訪問實現類的基礎方法。這假定您沒有完全控制客戶端運行時,即採取措施來防止反射。但是,如果你這樣做了,那麼你可能不需要擔心客戶端無法投入實現類。因此,如果你認爲這是一個針對不受信任的客戶端進程的潛在安全機制,那麼我就不會相信它。如果你能控制客戶端,那麼這可能足以讓錯誤的程序員避免造成無意的混亂。

2

我沒有看到這兩個包的優點。我建議這種替代:

package com.example.client ; 
    public interface Product 
    { 
     /* stuff */ 
    } 

    package com.example.client ; 
    public interface ProductFactory 
    { 
     Product make (X1 x1 , X2 x2 , /* parameters */ , Xn xn) ; 
    } 

    package com.example.manager; 
    interface ManagedProduct extends com.example.client.Product 
    { 
     /* management methods */ 
    } 

    package com.example.manager ; 
    public final class DefaultProductFactory implements com.example.client.ProductFactory 
    { 
     public static final DefaultProductFactory instance = new DefaultProductFactory () ; 

     private DefaultProductFactory () 
     { 
       super () ; 
     } 

     public ManagedProduct make (final X1 x1 , final X2 x2 , /* parameters */ , final Xn xn) 
     { 
       return new ManagedProduct () 
       { 
        /* implementation logic here */ 
       } ; 
     } 

     /* 
       possibly other methods 
       The Product implementation class is invisible. 
      */ 
    } 
  1. 採用兩個封裝不必要公開實施產品類的com.example.manager.DefaultProductFactory類。我認爲我的方法優於Bringer128's private inner class Factory。通過我的方法,實現Product類對於實現Factory類中可能存在的其他方法甚至是不可見的。
  2. 如果你做出最終的參數,那麼你就可以在實現產品類直接從方法的參數(不需要(1)建立X1 X1,X2 X2,使用它們... XN XN成員;(2) this.x1 = x1,this.x2 = x2,...,and this.xn = xn in the constructor; and(3)使用ProductImpl(x1,x2,...,xn)調用構造函數。 。雖小,但它可以節省你的按鍵
  3. 我強烈同意philwb這不應被視爲安全
  4. 這使得com.example.manager類具有相同的對象比其他包中的類上更多的方法 - 在Is this a good practice to use the "default" Java access to hide classes and methods from client要求。