Принудительно использовать шаблон Singleton для класса, реализующего интерфейс - PullRequest
6 голосов
/ 30 июля 2009

Я лучше объясню вопрос на примере. У меня есть Модель интерфейса , которую можно использовать для доступа к данным. Могут быть разные реализации Model, которые могут представлять данные в различном формате, например, XMl, txt и т. Д. Модель не имеет отношения к форматам. Допустим, одна из таких реализаций - myxmlModel .

Теперь я хочу заставить myxmlModel и любую другую реализацию Model следовать Singleton Pattern . Обычный способ сделать myxmlModels конструктор приватный и предоставляет статический метод фабрики для возврата экземпляра класса myModel. Но проблема в том, что интерфейс не может иметь статических определений методов, и в результате я не могу применить конкретное определение метода Фабрики ко всей реализации Модель . Таким образом, одна реализация может закончиться предоставлением getObject () , а другая может иметь get NewModel (). .

Обходной путь - разрешить доступ пакета к конструктору myxmlModel и создать класс Factory, который создает объект myxmlModel и кэширует его для дальнейшего использования.

Мне было интересно, есть ли лучший способ добиться такой же функциональности.

Ответы [ 5 ]

4 голосов
/ 30 июля 2009
  1. Сделать фабрику, которая возвращается экземпляры вашего интерфейса, модель.
  2. Сделайте все конкретные реализации из пакета моделей частных классов в той же упаковке, что и ваш завод.
  3. Если ваша модель должна быть одиночной, и вы используете Java 5+, используйте enum вместо традиционного синглтон, как безопаснее.
public enum MyXMLModel{  
INSTANCE();  
//rest of class  
};

EDIT: Другая возможность - создать классы делегатов, которые выполняют всю работу, а затем использовать перечисление для предоставления всех параметров модели.

например:

class MyXMLModelDelegate implements Model {
public void foo() { /*does foo*/}
...
}

class MyJSONModelDelegate implements Model {
public void foo() { /*does foo*/ }
...
}

public enum Models {
XML(new MyXMLModelDelgate()),
JSON(new MyJSONModelDelegate());

private Model delegate;
public Models(Model delegate) { this.delegate=delegate; }

public void foo() { delegate.foo(); }
}
2 голосов
/ 30 июля 2009

Вы можете использовать отражение. Примерно так:

public interface Model {
  class Singleton {
    public static Model instance(Class<? extends Model> modelClass) {
      try {
        return (Model)modelClass.getField("instance").get(null);
     } catch (blah-blah) {
       blah-blah
     }
  }
}

public class XmlModel implements Model {
  private static final Model instance = new XmlModel();

  private XmlModel() {
  }
}

использование:

Model.Singleton.instance(XmlModel.class)

На самом деле, мне не очень нравится этот код :). Во-первых, он использует рефлексию - очень медленно, во-вторых - возможны ошибки времени выполнения в случае неправильных определений классов.

0 голосов
/ 30 июля 2009

Это скорее ответ на ваш комментарий / уточнение к ответу кц. Неужели настоящая проблема заключается не в том, чтобы использовать шаблон Singleton, а в том, чтобы вместо него определить схему точек расширения затмения (равноденствия), которая позволяет вносить одиночный код?

Я думаю, этого нельзя сделать, потому что каждый раз, когда вы вызываете IConfigurationElement.createExecutableExtension, вы создаете новый экземпляр. Это совершенно несовместимо с вашими требованиями к синглтону. И поэтому вам нужен общедоступный конструктор по умолчанию, чтобы каждый мог создавать экземпляры.

Если вы не можете изменить определение точки расширения, чтобы плагины добавляли ModelFactory, а не модель, как

public interface ModelFactory {

  public Model getModelInstance();

}

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

Если я угадала неправильно, оставьте комментарий и я удалю ответ;)

0 голосов
/ 30 июля 2009

Я задавал себе тот же вопрос. И я предложил тот же ответ; -)

Теперь я обычно отбрасываю «форсированное» поведение, полагаюсь на документацию. Я не нашел ни одного случая, когда аспект синглтона был бы настолько убедительным, что его нужно было применять всеми средствами. Это просто «лучшая практика» для проекта.

Я обычно использую Spring для создания экземпляра такого объекта, и именно конфигурация Spring делает его Singleton. Безопасно и так просто ... плюс дополнительные преимущества Spring (такие как проксирование, замена одного объекта один раз для проведения некоторых испытаний и т. Д.)

0 голосов
/ 30 июля 2009

Можете ли вы реорганизовать интерфейс в абстрактный класс? Это позволит вам принудительно применить конкретный метод фабрики ко всем реализующим классам.

...