Java +Strategy + Factory + same package =如何隐藏特化类?

Java +Strategy + Factory + same package = how to hide specialized classes?

我想对同一个包的外部 classes 隐藏特化 classes。

示例:

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(){..}
}

为了实例化这些 classes,我使用了一个工厂....

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

注意,它们都在同一个包中,我不想将工厂和专门的 classes 放在子包中并更改专门化 classes 的默认构造函数(包)。

按照这个例子,我在同一个包中有第三个 class

package com.app.letter;

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

我只想由工厂提供 A 或 B LetterFactory.getInstance(doesNotMatter),它们在同一个包装中。

您可以通过将 A 和 B 设为包保护来从其他包中隐藏它们。

但这不会在同一个包中对 classes 隐藏它们。

由于它们必须对工厂可见,但对同一包的任何其他 class 不可见,唯一的方法是将它们设为 private static 嵌套 classes工厂 class.

使工厂的 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(){..}
   }
}

只有工厂知道这些 类 的存在并且可以实例化它们。

首先,我认为没有理由不允许直接实例化您的 classes。通常,您不关心谁实例化了 class,只要您确定它实例化 正确 即可。

因此,我相信你的问题不是一个,而是两个:

  1. 任何人 提供一种方法,以便在需要时手动正确创建 class A 和 class B
  2. 提供一种在给定一组抽象参数(您的工厂解决方案)的情况下实例化 AB 的方法。

至于第一部分,有 3 种方法可以正确实例化 class 不同复杂度的实体:

  1. 一个构造函数,其中包含所有必需参数和依赖项的列表。这可以很好地用于简单的情况。
  2. 一个工厂方法。这可以用于更复杂的场景。
  3. 工厂 class/a 建造者 class。这些通常用于复杂的场景。

现在,无论您选择哪个,按照所有逻辑都应该被允许 public。 constructor/factory method/factory class 将执行您的规则以创建 AB 的适当有效实例。而且,正如我之前提到的,当您不允许创建 class.

的完美且有效的实例时,没有任何可能的情况。

假设您使用构建器 class 作为最复杂的解决方案。您的代码可能如下所示:

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 来实现这一点。 此外,构建器方法是最复杂的方法,对于一些更简单的场景,您可能会使用一堆 public 静态工厂方法。然而,想法应该保持不变 - public 工厂方法应该确保它们只生成 A.

的有效实例

B class 的相同内容,在其他包中:

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
    }
}

我要补充一点,再次重申,您应该只隐藏系统中可能会以某些方式被滥用的部分。如果无法滥用 class 或方法,则没有必要隐藏它。因此,如果您提供了一种方法来正确初始化 AB 的有效实例,那么系统的其他部分可以看到或使用它对您来说应该无关紧要。