【问题标题】:Restrict Constructor to Sibling use - Java将构造函数限制为兄弟使用 - Java
【发布时间】:2011-07-15 08:45:25
【问题描述】:

这可能是不可能的,但我正在尝试创建一个只有共享超类的类才能访问的构造函数,这几乎是受保护修饰符的反向逻辑。我假设没有修饰符可以直接完成此操作,但是知道我要完成什么,有什么建议吗?

public Account extends SomeEntity {

    //default public
    public Account() {

    }

    // I am wanting this constructor to be only available to sibling classes.
    // (those that share the same super class )
    <modifier> Account(Element accountElement) {

    }
}


public Accounts extends SomeEntity {

    private List<Account> accountList;

    //default public
    public Accounts() {

        Account newAcct = new Account(element);

        //looped loading up Generic list of Account
        this.accountList.add(newAcct);
    }

我正在使用 RESTful Web 服务并根据 XML 响应构建对象,问题是如果我 GET 一个帐户列表,要将其构建到一个帐户对象列表中,我必须查询 Web 服务每个单独的帐户,即使我已经拥有这些信息,这似乎完全没有效率。

但是

我不想让我正在构建的 API 的普通用户能够以这种方式实例化帐户对象。 (使用Element

【问题讨论】:

  • 那你为什么要这样做?
  • 已更新以解释原因...@Thomas
  • 好吧,在这种情况下,这确实支持 bmargulies 的回答。获取您自己的专用包并创建最终课程!

标签: java oop inheritance access-modifiers siblings


【解决方案1】:

没有这样的语言结构。从 1.6 开始,包(=默认)访问是镇上唯一的 Java 机制。

我确信你可以用堆栈做一些讨厌的事情,但我不推荐它们。

【讨论】:

    【解决方案2】:

    我会看看工厂模式。您可能可以使用工厂方法的访问修饰符玩游戏以获得接近您想要的东西。您也许还可以在工厂方法中使用反射,以获得比包访问更接近您想要的东西。

    【讨论】:

      【解决方案3】:

      抱歉,我还是不明白这个设计的意义所在。如果一个方法被添加到一个类,它的实现可能只使用这个类的私有数据,因此不能保证“兄弟”类也可以使用这些数据。换句话说,如果您的愿望得到满足,您如何保证构造函数 Account(Object arg0) 实现不会将私有数据用于 Account 类? (因此对 Accounts 类不可见)

      在我看来,您似乎希望您的代码为单个帐户和帐户列表提供相同的接口 - 扩展 SomeEntity 类。这可以通过复合模式更优雅地完成。

      http://en.wikipedia.org/wiki/Composite_pattern

      如果您的意图是提供一个只有子类会使用的自定义构造函数,为什么不在 SomeEntity 中声明自定义构造函数并使这个类抽象?

      另外,记住你可以这样做:

      public Account() {
        this(new arg0());
      }
      
      Account(Object arg0) {
      
      }
      

      但不确定这是否有帮助。

      【讨论】:

        【解决方案4】:

        有一种方法可以模拟 C++ 的 friend 功能,从而达到您想要的结果。

        警告:这是一种人为的技术,只有在您没有其他解决方案时才应使用!

        由于在这种情况下没有修饰符可以满足您的要求,因此诀窍是将访问限制移动到另一个应用修饰符的地方。为此,向构造函数添加一个 key 参数。该键属于只能由允许的“兄弟”类(即给定类的子类)实例化的类。

        因此,限制被移到了公共超类,在那里可以使用通常的修饰符来限制键的创建。

        这是一个例子:

        public class CommonSuperClass {
            public static final class Key {
                private Key() {}
            }
        
            // This is the only way to create a key, and it's protected
            protected final Key createKey() {
                return new Key();
            }
        }
        
        public class Account {
            // The restricted constructor can even be public
            public Account(Key key) {
                // Everybody can try with null, but we're not that stupid
                // Of course any RuntimeException can be thrown instead
                if (key == null) throw new UnsupportedOperationException();
            }
        }
        
        public class AllowedSibling extends CommonSuperClass {
            public void foo() {
                // I'm allowed
                new Account(this.createKey());
            }
        }
        
        public class DeniedClass {
            public void foo() {
                // This doesn't compile
                new Account(new Key());
        
                // This will throw an exception
                new Account(null);
            }
        }
        

        【讨论】:

        • 一个简单的对象就可以了:protected final Object key = new Object()
        【解决方案5】:

        这是一个非常奇怪的必要条件,我认为没有访问修饰符可以做你想做的事。无论如何,我建议您将构造函数公开并将它们记录为“仅供内部使用”。

        如果你真的需要限制访问,你可以使用这个冗长的解决方案:

        public class Base {
            protected interface Factory {
                Base getInstance(Element e);
            }
        
            private static Map<Class<?>, Factory> registry = new HashMap<Class<?>, Factory>();
            protected static void register(Class<?> c, Factory f) { registry.put(c, f); }
            protected static <T extends Base> T create(Class<T> c, Element e) {
                return (T) registry.get(c).getInstance(e);
            }
        }
        
        public class Derived1 extends Base {
            protected Derived1(Element e) { }
            private static class Derived1Factory implements Factory {
                public Derived1 getInstance(Element e) {
                    return new Derived1(e);
                }
            }
        
            static {
                register(Derived1.class, new Derived1Factory());
            }
        }
        
        public class Derived2 extends Base {
            protected Derived2(Element e) { }
            private static class Derived2Factory implements Factory {
                public Derived2 getInstance(Element e) {
                    return new Derived2(e);
                }
            }
        
            static {
                register(Derived2.class, new Derived2Factory());
            }
        
            public void method() {
                Element e = null;
                ...
                // Put some element in e
                ...
                // This is what you were trying to do
                Derived1 d1 = create(Derived1.class, e);
            }
        }
        

        【讨论】:

        • 最终使用了默认的包访问,只是将文档块标记为(仅供内部使用)并将它们从文档中排除。认为这对我来说已经足够了。
        【解决方案6】:
        public class SomeEntity
            protected void init(Element accountElement) {}
        
        public class Account extends SomeEntity 
        
            public Account() 
                ....
        
            protected void init(Element accountElement)
                ....
        
        
        public class Accounts extends SomeEntity
        
            Account newAcct = new Account();
            newAcct.init(element);
        

        【讨论】:

          【解决方案7】:

          这是我会尝试的(我没有测试过这种方法):

          <modifier> Account(Object arg) {
              if (!super.getClass().isAssignableFrom(this.getClass())) {
                  throw new AssertionError("This constructor is only available to super classes.");
              } else {
                  // Continue...
              }
          }
          

          【讨论】:

          • 这看起来很有趣,但我想知道为什么会投反对票?
          • 应该反过来吗? if (!this.getClass().isAssignableFrom(super.getClass()))
          • 我没有对此投反对票,但它看起来有点没用。测试总是会失败(不会抛出任何断言)——子类总是可以分配给超类。这也不重要。 OP 希望限制对构造函数本身的访问,而不是限制构造对象的类型。
          • 对,this 是 Account 类,而不是试图使用构造函数的类。感谢您的澄清
          猜你喜欢
          • 2015-05-14
          • 2013-03-04
          • 2018-03-18
          • 1970-01-01
          • 2012-07-29
          • 2014-03-24
          • 1970-01-01
          • 2014-07-04
          • 2016-01-10
          相关资源
          最近更新 更多