Вы используете оператор switch для создания экземпляра на основе аргумента типа. В этом случае или, в основном, при использовании условных операций с типами данных, каждый раз, когда вы хотите расширить свое приложение, вам придется прикасаться к этим утверждениям путем добавления и изменения условий.
Легко представить, как это может сделать ваши проверки состояния взорваться.
Обратите внимание, что ваш пример скрывает зависимости, вводя фабрику или фабричные методы для создания конкретного типа вместо того, чтобы создавать его непосредственно в классе, где эта зависимость действительно существует.
Вы должны пытаться использовать фабрику только при создании экземпляра типа, который сложен для создания (например, вам нужно создать дополнительные типы для удовлетворения всех зависимостей) или если требуется дополнительная настройка. В этой ситуации можно использовать переключатель для проверки параметра, чтобы определить конфигурацию, применяемую к созданному экземпляру. Шаблон Builder также может быть полезен в этой ситуации.
Инкапсулируя сложную конструкцию или конфигурацию, вы также можете устранить дублирующийся код, поскольку все теперь в одном месте.
Чтобы исключить этот переключатель, я бы выделил каждую конструкцию типа в (при необходимости) отдельную фабрику, которая знает, как конструировать только этот тип. Таким образом, вместо метода ConnectorFactory.CreateDbConnector (тип) у вас должен быть
MySqlFactory.CreateConnector (арг)
и метод OracleDbFactory.CreateConnector () .
Когда переключатель типов исключается таким образом (фабрика каждого типа), введение нового типа требует только создания новой фабрики, которая предназначена только для этого типа. Нет изменений в существующем коде.
Учитывая, что вы можете изменить типы коннекторов из своего примера, было бы еще лучшим решением оставить плохие фабрики в покое, переместив каждый (фабричный) метод в объект, который они фактически создают: MySqlFactory.CreateConnector (args ) становится MySqlConnector.CreateInstance (args) . И здесь также метод инкапсулирует каждое условие, а в случае фабрики (метода) также примененные модификации экземпляра. Это означает, что если бы у нас был случай, когда мы создали соединитель только для чтения, мы теперь добавили бы к соединителю дополнительный метод с именем MySqlConnector.CreateReadOnlyInstance (args) (то же самое относится, если бы мы остались с фабриками ). Если вы хотите предоставить одноэлементный файл, вы должны ввести MySqlConnector.CreateSharedInstance (args) .
Поскольку каждый тип теперь имеет свой собственный метод фабрики, добавление нового типа в приложение не нарушит ничего существующего.
Если фабрика не требуется, я всегда создаю экземпляр типа непосредственно на месте.
Шаблон «Построитель» как решение также предлагает гибкий контроль над созданием экземпляров и инкапсулирует процедуру, и все это без необходимости использования оператора switch. Но конструктор снова должен быть связан только с одним единственным типом.
Если вам нужно быть расширяемым, например, Вы хотите заменить тип (или реализацию). Я бы реорганизовал его таким же образом, но затем вы должны реализовать все фабрики в соответствии с «Абстрактным шаблоном фабрики» и использовать инверсию зависимостей повсюду. Реализация всех типов должна происходить только на фабриках или фабричных методах. Ключевое слово "new" не разрешено нигде, кроме встроенных типов. Это уменьшает усилия, необходимые для изменения существующего кода, делая фабрики единственным местом, где нужно изменить конкретный тип. Как только вы это сделаете, вы также будете хорошо подготовлены к использованию внедрения зависимостей при желании.
Короче говоря, как правило, вы можете извлечь каждое условие переключения в отдельный метод с описательным именем, которое описывает случай. На этот раз звонящий вынужден выбрать требуемый метод (представляющий случай). Звонящий, конечно, уже знает все о себе (также свой собственный тип, как в вашем примере). Он также будет знать, какие действия он любит выполнять. Нет необходимости переключаться, чтобы выбрать правильное действие.
И, учитывая принцип «говорите, не спрашивайте», не следует размещать переключатель внутри второго типа, чтобы решить, какое действие выполнить с первым типом. Первый тип должен вызывать соответствующий метод для выполнения предполагаемого действия с его данными или от его имени.
И не каждое утверждение switch является нарушением, и нарушение принципа - это нормально, если вы теперь последствия. Например. было бы хорошо использовать переключатель для проверки частного флага. Оператор switch эквивалентен вложенному оператору if-then-else. Следует избегать переключения типа, например, используя наследование и определяя хорошие интерфейсы для границ. Когда вы используете, например, Полиморфизм и инверсия зависимостей вам, скорее всего, не понадобятся для проверки типов.