новый экземпляр класса против класса Singleton против статического метода - PullRequest
3 голосов
/ 30 августа 2011

Я изо всех сил пытаюсь выбрать идеальный шаблон дизайна для этого сценария:

Когда я нажимаю кнопку «Обзор» в моем пользовательском интерфейсе Swing, указанный URL-адрес должен быть открыт в веб-браузере.Эта функциональность достигается внутри этого служебного класса, который выглядит следующим образом:

//inside action Listener of the browse button I call the openURL method of the below class

class webBrowserUtility(){
    void openURL(String url){
    ........
    }
}

Методы шаблона проектирования

Подход 1) Я могу пойти дальше и создать новый экземплярвыше класса и вызовите openURL ().

подход 2) Singleton: сделайте класс WebbrowserUtility одноэлементным и сохраните статический экземпляр этого класса в памяти, чтобы иметь возможность вызывать метод при необходимости.

Подход 3) статический метод: Сделайте метод openURL () статическим и при необходимости вызовите WebbrowserUtility.openURL (url).

В моем первом подходе я боюсь, что он может быть неэффективным, так как, каждое нажатие на кнопку обзора создаст новый экземпляр класса WebBrowserUtility.Я запутался между подходами к выбору 2) и 3).Не могли бы вы помочь мне выбрать лучший из этих трех шаблонов проектирования для этого сценария?Или есть лучший дизайн шаблона, который может быть адаптирован для того же?

Ответы [ 6 ]

5 голосов
/ 30 августа 2011

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

Я имею в виду, что в вашем случае это не очевидно: с одной стороны вы должны использовать одноэлементный экземпляр, поэтому не нужно создавать много экземпляров, потреблять больше памяти и вносить дополнительные издержки при создании объекта. Однако, с другой стороны, вы не можете быть уверены, что требования вашего проекта не изменятся - возможно, вам придется добавить какое-то состояние к вашей WebBrowserUtility услуге и выполнить несколько вызовов параллельно, сохраняя разные состояния для разных потребителей, или Вы можете даже реализовать пул экземпляров для своего класса. Вы не можете предсказать будущее, поэтому вы должны использовать абстракцию.

Самый простой способ абстрагировать создание объекта - это использовать статический фабричный метод и назвать его как getInstance() - точно так же, как если вы собираетесь реализовать синглтон, хотя и не думайте об этом только с точки зрения одноэлементной реализации - это скорее просто абстракция того, как его реализовать. На данный момент вы можете придерживаться singleton, так что этот метод всегда будет возвращать единственный экземпляр службы, хотя в будущем, если вам потребуется изменить способ создания класса, вы просто измените реализацию getInstance() без необходимости изменять какие-либо код, который на самом деле использует ваш сервис. Так что вам не придется решать, какой путь лучше, пока у вас не будет достаточно информации для выбора.

Таким образом, создание экземпляров ваших служб с помощью фабричных методов дает вам больше гибкости, однако есть и лучшие способы. Если вы продолжите развивать эту идею об абстракции экземпляра, вы поймете, что обычно вы хотите переместить код создания из фактического сервиса в выделенный фабричный класс , потому что иногда вы хотите создать один и тот же сервис в другом пути для разных средств. Дальнейшее развитие этой идеи заканчивается использованием шаблона Inversion of Control , который является окончательным ответом о том, как создавать экземпляры ваших служб и управлять зависимостями между ними.

Если вы используете Java, взгляните на очень популярную Spring Framework , которая позволяет вам определять правила создания сервисов в файле конфигурации, поэтому, если вам нужен прототип вместо синглтона, это только вопрос изменения этого конфигурационного файла.

Я бы также не рекомендовал реализовывать ваш класс обслуживания как набор статических методов с необходимой логикой. Причина этого - это может быть просто и быстро реализовать это прямо сейчас, однако в будущем ваши руки будут связаны с интерфейсом, который определяет статические методы. Поэтому, если вам в конечном итоге потребуется использовать несколько экземпляров, вам придется изменить код потребителей, который также использует ваши статические методы, потому что статические сигнатуры находятся в вашем интерфейсе, а не только в вашей реализации. В отличие от этого, выбор между прототипом / синглтоном скрыт в коде создания экземпляра, поэтому потребителям все равно, как создается экземпляр, - они просто запрашивают экземпляр и получают его.

2 голосов
/ 30 августа 2011

Лично я бы выбрал подход 3, поскольку, поскольку область действия этого примера расширяется, нет необходимости хранить состояние объекта, и есть непосредственное использование из обработчика щелчков.

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

Надеюсь, это поможет.

2 голосов
/ 30 августа 2011

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

Итак, вопрос в том, использует ли ваш WebBrowserUtility какие-либо нестатические переменные-члены (т.е. данные экземпляра) вашего класса?

  • Если это так, то вам нужно перейти к подходу 1. и каждый раз создавать новый экземпляр.

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

2 голосов
/ 30 августа 2011

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

1 голос
/ 30 августа 2011

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

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

0 голосов
/ 30 августа 2011

Нужно ли сохранять состояние в классе WebBrowserUtility (например, переменные-члены, счетчики, ...)?

Если да: требуется ли это состояние для глобальной доступности или синхронизации?Подход 2 ... в противном случае 1)

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

...