Ограничить использование конструктора Sibling - Java - PullRequest
0 голосов
/ 15 марта 2011

Это может быть невозможно, но я пытаюсь создать конструктор, к которому могут обращаться только классы с общим классом, почти обратная логика защищенного модификатора. Я предполагаю, что нет модификатора, чтобы выполнить это напрямую, но, зная, что я пытаюсь сделать, какие-либо предложения?

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 и строю объекты из ответов XML, проблема в том, что если я GET перечислю учетные записи, чтобы встроить их в список объектов учетных записей, для которых мне нужно было бы запросить веб-службу каждая отдельная учетная запись, хотя у меня уже есть информация, и это кажется совершенно неэффективным.

НО

Я не хочу давать обычному пользователю API, который я создаю, возможность создавать объект Account таким образом. (С Element)

Ответы [ 7 ]

3 голосов
/ 15 марта 2011

Нет такой языковой конструкции.Пакетный доступ (= по умолчанию) - единственный Java-механизм в городе, начиная с 1.6.

Я уверен, что вы могли бы делать неприятные вещи со стеком, но я бы не рекомендовал их.

1 голос
/ 15 марта 2011

Существует способ эмулировать функцию друга в C ++ и таким образом достичь желаемого результата.

Предупреждение. Это искусственная техника, которую следует использовать, только если у вас нет другого решения!

Поскольку в этом случае ни один модификатор не делает то, что вам нужно, уловка состоит в том, чтобы переместить ограничение доступа в другое место, где применяются модификаторы. Для этого добавьте параметр 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);
    }
}
1 голос
/ 15 марта 2011

Извините, но я до сих пор не понимаю смысл этого замысла. Если метод добавлен в класс, его реализация, вероятно, будет использовать личные данные только для этого класса, и, следовательно, для «родственных» классов нельзя гарантировать, что эти данные также доступны для них. Другими словами, если бы ваше желание было выполнено, как бы вы гарантировали, что реализация конструктора Account (Object arg0) не будет использовать личные данные для класса Account? (и поэтому невидимы для класса учетных записей)

Мне кажется, что вы хотите, чтобы ваш код предоставлял один и тот же интерфейс для одной учетной записи и списка учетных записей - расширяя класс SomeEntity. Это может быть выполнено более изящно с составным образцом.

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

однако, если вы намереваетесь предоставить пользовательский конструктор, который будут использовать только подклассы, почему бы не объявить пользовательский конструктор в SomeEntity и сделать этот класс абстрактным?

также помните, что вы можете сделать это:

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

Account(Object arg0) {

}

Не уверен, что это поможет, хотя.

1 голос
/ 15 марта 2011

Я бы посмотрел на заводскую модель.Вероятно, вы можете играть в игры с модификаторами доступа фабричного метода (методов), чтобы получить что-то близкое к тому, что вы хотите.Вы также можете поиграть с отражением внутри фабричного метода, чтобы получить что-то ближе к тому, что вы хотите, чем то, что вам дает доступ к пакету.

0 голосов
/ 15 марта 2011
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);
0 голосов
/ 15 марта 2011

Это очень странный реквизит, и я думаю, что никакой модификатор доступа не может делать то, что вы хотите. В любом случае, я рекомендую вам просто сделать конструкторы общедоступными и задокументировать их как «только для внутреннего использования».

Если вам действительно нужно ограничить доступ, вы можете использовать это многословное решение:

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);
    }
}
0 голосов
/ 15 марта 2011

Вот что я бы попробовал (я не проверял этот метод):

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