简体   繁体   English

Java +策略+工厂+相同的程序包=如何隐藏专门的类?

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

I want to hide the specialization classes from the external classes of the same package. 我想从同一包的外部类中隐藏专业化类。

Example: 例:

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

To instantiate these classes I use a factory.... 为了实例化这些类,我使用了一个工厂。

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

Note, all of them are in the same package and I DO NOT WANT to put the factory and the specialized classes in a sub package and change the specialization classes' constructors to default (package). 请注意,它们都在同一个包中,并且我不想将工厂类和专门类放在子包中,并且将专门类的构造函数更改为default(包)。

Following this example, I have a third class in the same package 在这个例子之后,我在同一个程序包中有一个第三类

package com.app.letter;

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

I want to provide the A or B only by the factory LetterFactory.getInstance(doesNotMatter) which is in the same package. 我只想由位于同一包中的工厂LetterFactory.getInstance(doesNotMatter)提供A或B。

Make A and B private static classes of the factory: 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(){..}
   }
}

Only the factory knows the existence of these classes and can instanciate them. 只有工厂知道这些类的存在并可以实例化它们。

First of all, I see no reason to not allow to instantiate your classes directly. 首先,我认为没有理由不允许直接实例化您的类。 Usually, you do not care who instantiated the class, as long as you are sure it was instantiated correctly . 通常,只要确定已正确实例化了该类,您就不必在意谁实例化了该类。

Therefore, I believe you have not one problem, but two: 因此,我相信您不是一个问题,而是两个:

  1. Provide a way for anyone to correctly create both class A and class B manually, if required. 如果需要,为任何人提供一种手动正确创建A类和B类的方法。
  2. Provide a way to instantiate either A or B given some set of abstract parameters (your Factory solution). 提供一种在给定一些抽象参数的情况下实例化AB的方法(您的Factory解决方案)。

As for the first part, the are 3 ways to instantiate classes of different complexity correctly: 对于第一部分,有3种方法可以正确地实例化具有不同复杂度的类:

  1. A constructor, which has a list of all required parameters and dependencies. 构造函数,其中包含所有必需参数和依赖项的列表。 This can be used for simple cases pretty well. 这可以很好地用于简单的情况。
  2. A factory method. 一种工厂方法。 This can be used for more complex scenarios. 这可以用于更复杂的方案。
  3. A factory class/a builder class. 工厂类/建造者类。 These are usually used for complex scenarios. 这些通常用于复杂的场景。

Now, whichever one you choose, by all logic it should be allowed to be public. 现在,无论您选择哪种方式,都应该允许其公开。 The constructor/factory method/factory class will enforce your rules to create a proper valid instance of either A or B . 构造函数/工厂方法/工厂类将强制您的规则创建AB的适当有效实例。 And, as I mentioned before, there is no possible scenario when you should disallow creating a perfectly good and valid instance of a class. 而且,正如我之前提到的,在任何情况下都不应该禁止创建一个完美且有效的类实例。

Let's say you went with a builder class as the most complex solution. 假设您选择了一个构建器类作为最复杂的解决方案。 Here's how your code might look: 这是您的代码外观:

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

The builder should be designed in a thought in mind, that it could not in any way produce an invalid instance of A . 构建器的设计应考虑到不能以任何方式产生A的无效实例。 This way, you can allow the builder to be the only way of instantiating A and not worrying about it, because all instances it creates are always valid. 这样,您可以允许构建器成为实例化A而不用担心的唯一方法,因为它创建的所有实例始终有效。 You can utilize proper API on the builder or Exceptions to reach this. 您可以在构建器上使用适当的API或“异常”来达到此目的。 Also, the builder approach is the most complex one, for some simpler scenarios you might use a bunch of public static factory methods. 同样,构建器方法是最复杂的方法,对于某些更简单的方案,您可能会使用大量公共静态工厂方法。 However the idea should remain the same - the public factory methods should ensure that they produce only valid instances of A . 但是,想法应该保持不变-公共工厂方法应确保它们仅产生A有效实例。

Same stuff for B class, in other package: B类的其他材料,在其他包装中:

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

Now for the factory. 现在为工厂。 Basically same thing you had, but with builders: 基本上与您相同,但具有构建器:

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();
        }
    }
}

And about the usages: 关于用法:

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

I will add, repeating myself once again, you should only hide the parts of your system that can be abused in some ways. 我将补充一遍,再次重复自己,您只应隐藏系统中可能以某种方式滥用的部分。 There is no point of hiding a class or a method if there is no way for it to be abused. 如果无法滥用类或方法,则没有任何隐藏的意义。 Therefore, if you provide a way to correctly initialize a valid instance of A or B it should not matter to you that some other part of the system can see it or use it. 因此,如果您提供了一种正确初始化AB的有效实例的方法,那么系统的其他部分可以看到或使用它就无关紧要。

You can hide A and B from other packages by making them package-protected. 您可以通过使A和B处于受软件包保护的状态来对其他软件包隐藏。

But that won't hide them from classes in the same package. 但这不会将它们隐藏在同一包的类中。

Since they have to be visible by the factory, but not by any other class of the same package, the only way to do that is to make them private static nested classes of the factory class. 由于它们必须在工厂中可见,而在同一包的任何其他类中则不可见,所以唯一的方法是使它们成为工厂类的私有静态嵌套类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM