2011-07-21 26 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要求。