Что является более злым:ненужный синглтон или Божественный объект?

StackOverflow https://stackoverflow.com/questions/1079883

Вопрос

Вот такая ситуация:У меня есть класс, который делает слишком много.В основном он предназначен для доступа к информации о конфигурации, но у него также есть подключение к базе данных.Он реализован как синглтон, так что это также затрудняет модульное тестирование, поскольку большая часть кода довольно тесно связана с ним.Это еще более проблематично, поскольку создает зависимость от времени импорта (мы делаем это на Python), что означает, что определенные модули должны быть импортированы в определенном порядке.В идеале я бы хотел разделить это на два класса и сделать его не одноэлементным.

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

Итак, я вижу здесь три варианта:

  1. Разбейте объект конфигурации на (одноэлементный) объект конфигурации и (не одноэлементный) объект базы данных.Это, по крайней мере, позволило бы мне удалить базу данных как зависимость от времени импорта.
  2. Сделайте объект конфигурации не одноэлементным и передайте его объектам, которым это необходимо.Я чувствую, что это лучше отвечает нашим краткосрочным потребностям, но я думаю, что это заняло бы значительно больше времени.
  3. Сделайте то, о чем я не подумал, и что вы предлагаете в своем ответе.:-)

Так что же мне делать?

Это было полезно?

Решение

Я думаю, вы на пути к разделению на два класса.Возможно, вы захотите рассмотреть возможность использования фабрики для создания контекста базы данных / подключения по мере необходимости.Таким образом, вы можете рассматривать соединение как единицу рабочего объекта, которая создается / утилизируется по мере необходимости, а не сохранять одно соединение в течение всего срока службы объекта.Тем не менее, YMMV.

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

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

Другие советы

Это трудно понять, не видя вашего кода, но почему бы не делать то, что вы говорите - делать это постепенно?Сначала выполните шаг 1, разделите базу данных.

Если это быстро, то вернитесь назад, и теперь у вас есть только 1 объект меньшего размера, чтобы перестать быть синглтоном, а не 2.Таким образом, шаг 2 должен быть быстрее.Или на этом этапе вы можете увидеть какой-то другой код, который может быть переработан из синглтона.

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

Например, возможно, можно было бы сделать одну часть конфигурации одноэлементной за раз, если части конфигурации независимы.Так что, может быть, конфигурация GUI оставила singleton, в то время как fileconfiguration была переработана, или что-то подобное?

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

Наличие объекта cofiguration в виде синглтона всегда идеально подходило для меня.Существует только один файл конфигурации, и я всегда хочу прочитать его при запуске приложения.

Извините за то, что я не знаю никакого Python, поэтому я надеюсь, что любой псевдокод имеет смысл...

Сначала я бы разделил объект на две части, чтобы уменьшить обязанности вашего синглтона, затем я бы взял оставшийся синглтон конфигурации и превратил его в обычный класс (как будто вы собираетесь выполнить свое второе предложение).

Как только я зайду так далеко, я создам новый синглтон-оболочку, который предоставляет методы класса configuration:

class ConfigurationWrapper : IConfigurationClass 
{
    public static property ConfigurationWrapper Instance;

    public property IConfigurationClass InnerClass;

    public method GetDefaultWindowWidth()
    {
        return InnerClass.GetDefaultWindowWidth();
    }

    etc...
}

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

ConfigurationClass config = new ConfigurationClass()
ConfigurationWrapper.Instance.InnerClass = config;

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

С другой стороны, вы можете проигнорировать рефакторинг обычаев и просто внедрить издевательский класс конфигурации в оболочку singleton для тестирования - по сути, внедрение зависимостей бедняком.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top