Ограничение создания класса одной фабрикой - PullRequest
1 голос
/ 16 мая 2011

У меня есть класс, и я хотел бы ограничить его создание только одним классом Factory. Как я могу предотвратить создание этого объекта оператором new?

Ответы [ 6 ]

4 голосов
/ 16 мая 2011

Сделать все пакеты конструкторов приватными;есть один объект Factory в том же пакете, который владеет общедоступным методом создания для клиентов вне пакета.

Это легко сделать с одним классом, но я предполагаю, что вы хотите, чтобы эта Factory былавиртуальный: способен создавать несколько реализаций одного интерфейса или абстрактного класса.

1 голос
/ 16 мая 2011

Более простой подход - доверять другому классу в том же пакете.

Таким образом, конструктор имеет область действия по умолчанию, и Factory должен находиться в том же пакете.


Однакочтобы ответить на ваш вопрос, вы можете сделать Factory внутренним классом, который он может вызвать приватным конструктором внешнего класса.например,

public class MyObject {
    private MyObject() { }

    public static class Factory {
         public MyObject create() {
             // can call private members of the outer class.
             return new MyObject(); 
         }
    }
}

MyObject.Factory mof = new MyObject.Factory();
MyObject mo = mof.create();

Использование этого подхода ограничивает доступ к внутренним и вложенным классам.

1 голос
/ 16 мая 2011

Jigar - правильный ответ на ваш вопрос, однако это анти-шаблон с серьезными недостатками:

http://en.wikipedia.org/wiki/Singleton_pattern#Drawbacks

http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx

Я бы посоветовал вам взглянуть на проект системы, прежде чем внедрять такое решение. Никогда не нужно блокировать создание экземпляров класса так, как вы описали.

1 голос
/ 16 мая 2011

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

public interface FooBehavior { ... }
public class FooFactory {
    private static FooFactory factory = new FooFactory();
    private FooFactory() { ... }
    class Foo implements FooBehavior { ... }
    public static FooBehavior createFoo() {
        return factory.new Foo();
    }
}

Экземпляры Foo связаны с жизненным циклом фабрики. Поскольку экземпляр фабрики требуется для создания экземпляра Foo, а единственный экземпляр фабрики содержится внутри фабрики, только фабрика может создавать экземпляры Foo.

Кроме того, будьте осторожны при использовании одноэлементного шаблона.

0 голосов
/ 16 мая 2011

Другой шаблон, который начинает заменять шаблон Singleton, использует перечисления:

public enum Factory { INSTANCE;

  public SomeObject create(Params someParams) {
    if (isTypeA(someParams))
      return new TypeASubclass();
    else if (isTypeB(someParams))
      return new TypeBSubclass();
    else
      return new SomeDefaultObject();
  }
}

Вы будете использовать его стандартным способом:

SomeObject someObject = Factory.INSTANCE.create(myParams);

и enum, что гарантируетв системе есть только одна фабрика *)


*) с обычными ограничениями на загрузчик одного на jvm / один на класс

0 голосов
/ 16 мая 2011

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

Вы можете запросить стек из текущего потока, выполнив что-то вроде -

StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
if ("your.package.Factory".equals(stackTrace[1].getClassName()) {
    instantiateClass();
} else {
    throw new InstantiationException("Can only instantiate from factory");
}

Вам нужно проверить, какой это StackTraceElement, но это должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...