2015-11-13 38 views
2

我想隐藏来自同一个包的外部类的特化类。Java + Strategy + Factory +相同的包=如何隐藏专门的类?

例子:

package com.app.letter; 
public interface LetterChange { 
    void change(); 
} 

public class A implements LetterChange{ 
    public void change(){..} 
} 

public class B implements LetterChange{ 
    public void change(){..} 
} 

将这些类别实例我使用一个工厂....

package com.app.letter; 
public class LetterFactory{ 
    public static LetterChange getInstance(Object doesNotMatter){ 
    return doesNotMatter.isA() ? new A() : new B(); 
} 

注意,所有的人都在同一个包和我不想到将工厂和专用类放在一个子包中,并将专业化类的构造函数更改为默认(包)。

遵循此实例,我有第三类在同一包

package com.app.letter; 

public class DoesNotMatterClass{ 
    public void situations(){  
     LetterFactory.getInstance(null); // Legal 
     new A(); Illegal 
     new B(); Illegal  
    } 
} 

我想只由工厂LetterFactory.getInstance(doesNotMatter),它是在相同的封装,以提供A或B。

+1

有趣的是,您担心在同一个包中执行非法事件的类。它在某些方面类似于访问类的私有成员的类中的代码,而不是通过公共方法。通常我们隐藏了一些东西,因为如果我们改变它们,我们不希望代码破坏。您是否希望包中的开发人员在不知道风险的情况下访问A和B?另外,我认为如果该功能使用Java 9中的模块,则可以使用Java 9中的Module执行此操作。 – Fuhrmanator

回答

4

制作AB私人静态类工厂:

public class LetterFactory{ 
    public static LetterChange getInstance(Object doesNotMatter){ 
     return doesNotMatter.isA() ? new A() : new B(); 
    } 

    private static class A implements LetterChange{ 
     public void change(){..} 
    } 

    private static class B implements LetterChange{ 
     public void change(){..} 
    } 
} 

只有厂家知道这些类的存在,并可以实例化他们。

0

您可以将其他软件包中的A和B隐藏起来,使其受到软件包保护。

但是,这不会将它们隐藏在相同包中的类中。

由于它们必须是工厂可见的,但不能被任何其他类相同的包所看到,唯一的方法是使它们成为工厂类的私有静态嵌套类。

+0

他不想那样做。他想要一个替代品来创建一个专门的软件包。 – kauedb

+0

我从来没有建议创建一个专门的软件包。他现在可能想要使A和B私有静态嵌套类,但这是实现他想要的目标的唯一方法,所以... –

+0

@JB Nizet,案件是,我不想实例化A和B从同样的包装,只有工厂。 但是,谢谢你的回答 – Bevilaqua

2

首先,我没有理由不允许直接实例化你的类。通常,你不关心谁实例化了这个类,只要你确定它实例化了就可以

因此,我相信你有没有一个问题,而是两个:

  1. 提供一种方法来正确地创建这两个手动,如果需要的话类A和类B
  2. 提供一种实例化给定一组抽象参数(工厂解决方案)的AB的方法。

对于第一部分,3种方法来正确地实例化不同复杂性的类:

  1. 构造函数,它具有所有必需的参数和依赖关系的列表。这可以用于很简单的情况。
  2. 工厂方法。这可以用于更复杂的场景。
  3. 工厂类/构建器类。这些通常用于复杂场景。

现在,无论您选择哪一个,都应该允许所有逻辑公开。构造函数/工厂方法/工厂类将强制您的规则创建AB的适当有效实例。而且,正如我之前提到的,当你不应该创建一个完美的,有效的类的实例时,没有可能的情况。

假设您将建造者类作为最复杂的解决方案。这里是你的代码的外观:

package com.app.letter.A; 
public class A { 
    A() { //Package visibility, we don't want anyone to create an invalid A class 
     ... 
    } 
    ... 
} 

public class ABuilder { 
    public void validateAndSetSomeCriticalParam(Param param) { 
     ... 
    } 
    public A build() { 
     A a = new A(); 
     a.setSomeCriticalParam(param); 
     ... 
     return a; 
    } 
} 

建设者应该在心中的思想进行设计,它不能以任何方式产生的A无效的实例。这样,您可以允许构建器成为实例化A而不必担心的唯一方式,因为它创建的所有实例始终有效。您可以在构建器上使用适当的API或例外来达到此目的。 另外,构建器方法是最复杂的方法,对于一些更简单的场景,您可能会使用一些公共静态工厂方法。但是这个想法应该保持不变 - 公共工厂方法应该确保它们只生成A的有效实例。

为B级同样的东西,在其他包:

package com.app.letter.B; 
public class B { 
    ... 
} 
public class BBuilder { 
    ... 
} 

现在的工厂。基本上同样的事情,你有,但建设者:

package com.app.letter; 
public class LetterFactory{ 
    public static LetterChange getInstance(Object doesNotMatter){ 
     if (doesNotMatter.isA()) { 
      ABuilder builder = new ABuilder(); 
      builder.setSomeCriticalParam(...); 
      builder... 
      return builder.build(); 
     } else { 
      BBuilder builder = new BBuilder(); 
      builder.setSomeBSpecificParam(...); 
      builder... 
      return builder.build(); 
     } 
    } 
} 

约在用法:

public class DoesNotMatterClass{ 
    public void situations(){  
     LetterFactory.getInstance(..whatever..); // Legal 
     new A(); //Illegal, as it is package protected 
     new B(); //Illegal, as it is package protected 
     new ABuilder(); //Legal, as ABuilder can ensure that only valid As are created 
     new BBuilder(); //Legal, as BBuilder can ensure that only valid Bs are created 
    } 
} 

我会添加,再次重复自己,你应该只隐藏你的系统的部分,可以是在某些方面受到虐待。如果没有办法让它被滥用,那么就没有必要隐藏一个类或一个方法。因此,如果您提供了正确初始化AB的有效实例的方法,则系统的其他某个部分可以看到它或使用它并不重要。

+0

我明白你的解释,这非常有用。谢谢。 这个问题的整个问题是因为我的项目的架构被描绘为如果包代表资源(web服务项目)并且保持当前的架构,我不想创建一个只适用策略的包或者“保证”我的实例构建正确。例如: com.app。用户(用户资源) com.app.user.address(用户的地址资源) 如果我创建另一个包意味着一个新资源(至少现在)。总之,为了保持它,我宁愿遵循WilQu的方法。 – Bevilaqua

+0

我看到隐藏A和B(以及使用工厂)的优点与将类成员私有化相同:您可以更改它们,并且客户端不会知道发生了什么(或者直接使用它们会中断)。换句话说,无论是隐藏的都可以在不破坏客户端代码的情况下进行更改 – Fuhrmanator

+0

@Fuhrmanator是的,那是当你用一个公共工厂在同一个软件包中分离软件包可见的A和B.但是,OP想要添加更多的类到那个无法访问A和B的包中。在我看来,这不是一个合适的解决方案,因为它带来了非常紧密的耦合和巧合的包级别内聚。我的解决方案是重新包装并提供适当的公共API。 WilQu提供的解决方案与此相反 - 消除公共API并引入最强大的耦合形式,这也是在可以牺牲灵活性的情况下合理的解决方案。 – bezmax