Использование функционального программирования / языки в рамках разработки ядра ОС.
В блоге Google Testing есть серия записей об отказе от синглтона (для создания тестируемого кода). Может быть, это может вам помочь:
В последней статье подробно объясняется, как переместите создание новых объектов в фабрику, чтобы избежать использования синглтонов. Обязательно стоит прочитать.
Короче говоря, мы перемещаем всех новых операторов на фабрику. Мы группируем все объекты с одинаковым сроком службы в одну фабрику.
Лучше всего использовать вместо него заводской шаблон. Когда вы создаете новый экземпляр своего класса (в фабрике), вы можете вставить «глобальные» данные во вновь созданный объект, либо как ссылку на единственный экземпляр (который вы храните в фабричном классе), либо скопировав соответствующий данные в новый объект.
Все ваши объекты будут содержать данные, которые раньше жили в синглтоне. Я не думаю, что в целом есть большая разница, но это может облегчить чтение вашего кода.
Я мог бы сказать очевидное здесь, но есть ли причина, по которой вы не можете использовать структуру внедрения зависимостей, такую как Spring или Guice ]? (Я считаю, что Spring теперь также доступен для .NET.)
Таким образом, фреймворк может содержать единственную копию объектов конфигурации, и вашим bean-компонентам (службам, DAO и т. Д.) Не нужно беспокоиться о ищу его.
Я обычно использую такой подход!
Если вы используете Spring Framework , вы можете просто создать обычный компонент. По умолчанию (или если вы явно установили scope = "singleton"
) создается только один экземпляр компонента, и этот экземпляр возвращается каждый раз, когда компонент используется в зависимости или извлекается через getBean ( )
.
Вы получаете преимущество единственного экземпляра без связывания паттерна Singleton.
Альтернатива - передать то, что вам нужно, вместо того, чтобы просить объект о вещах.
не накапливают ответственность за один объект конфигурации , так как он заканчивается очень большим объектом, который сложно понять и хрупко.
Например, если вам нужен другой параметр для определенного класса, вы меняете объект Configuration
, а затем перекомпилируете все классы, которые его используют. Это несколько проблематично.
Попробуйте провести рефакторинг своего кода, чтобы избежать общего, глобального и большого объекта Configuration
. Передавайте только необходимые параметры клиентским классам:
class Server {
int port;
Server(Configuration config) {
this.port = config.getServerPort();
}
}
следует реорганизовать на:
class Server {
public Server(int port) {
this.port = port;
}
}
инфраструктура внедрения зависимостей здесь очень поможет, но это не обязательно.
Вы можете добиться того же поведения синглтона, используя статические методы. Стив Йегге очень хорошо объясняет это в этой статье .
Возможен ли класс, содержащий только статические методы и поля? Я не совсем уверен в вашей ситуации, но, возможно, стоит разобраться.
Зависит от того, какие инструменты / фреймворки и т. Д. Используются. С помощью инструментов внедрения зависимостей / ioc можно часто по-прежнему получить производительность / оптимизацию одноэлементного объекта, если контейнер di / ioc использует одноэлементное поведение для требуемого класса (например, интерфейс IConfigSettings), создав только один экземпляр класса. Это все еще может быть заменено для тестирования
В качестве альтернативы можно использовать фабрику для создания класса и возврата одного и того же экземпляра каждый раз, когда вы его запрашиваете - но для тестирования он может вернуть заглушенную / имитацию версии
Проверьте возможность настройки в качестве интерфейса обратного вызова. Таким образом, ваш чувствительный к конфигурации код будет выглядеть:
MyReuseCode.Configure(IConfiguration)
Код инициализации системы будет выглядеть:
Library.init(MyIConfigurationImpl)
Вы можете использовать структуру внедрения зависимостей, чтобы облегчить боль при передаче объекта конфигурации. Приличный вариант - ninject , преимущество которого заключается в использовании кода, а не xml.
Возможно, тоже не очень чисто, но вы могли бы передать биты информации, которые хотите изменить, методу, который создает синглтон - вместо использования
public static Singleton getInstance() {
if(singleton != null)
createSingleton();
return singleton;
}
}
вы можете вызвать createSingleton (Информация)
непосредственно при запуске приложения (и в setUp-методах модульных тестов).