Чтобы исключить переключение типа, вы должны переместить обязанности обратно к типу, который требует определенного типа действия.Этот тип, в вашем случае «Пользователь», имеет всю информацию о себе и может легко вызвать правильную операцию на основе этих знаний.И вы должны использовать наследство.
В вашем случае вам придется отражать пользовательские типы с помощью простого наследования или с помощью композиции.Ваш «пользователь» будет иметь свойство «UserType», как в вашем примере, но вместо того, чтобы делать его просто как тип «Enum», он становится сложным типом, который наследует интерфейс «IUserType» и знает, как создать его конкретныйзависимости (UserType реализует IUserType).«IUserType» может предоставлять атрибуты, специфичные для типа, через свойство (например, «IUserType.TypeSpecificTree», которое возвращает «ITypeSpecificTree»).
Так что, когда в вашем примере «Пользователь» повышен до «премиум», вы простоустановите для свойства новый экземпляр конкретной реализации «IUserType» (например, PremiumUserType »), которая выполняет свои конкретные действия, такие как построение премиального дерева (реализация« ITypeSpecificTree ») из вашего примера, а также создание связанных типов.
Таким образом, оператор switch устраняется с помощью композиции и наследования. Мы преобразовали сложное свойство «UserType» в отдельный класс, а затем перенесли специфические для типа обязанности в сам тип. Наследование и особенно инверсия зависимостей помогли работать с объектом(например, получение информации о типе пользователя, например (User.IUserType.IUserSpecificTree ") без знания конкретного типа. Это помогло убедиться, что мы открыты для расширения . НаследоватьКроме того, ce помог инкапсулировать поведение, специфичное для типа, чтобы сделать наш код закрытым для модификации .
Если нам нужно внести изменения в то, как генерируется дерево, специфичное для типа, или как ведет себя этот тип пользователя, мыбудет касаться только связанной реализации «IUserType», но не «пользователь».Если добавляются новые типы пользователей (расширение), им необходимо будет реализовать базовый интерфейс «IUserType», и никакой другой код, например операторы-переключатели, не должен затрагиваться, чтобы заставить его работать, и больше никаких проверок типов не требуется.И чтобы сделать его завершенным и предложить некоторую более расширяемость, класс «Пользователь» должен также реализовать интерфейс, например «IUser», который предоставляет тип пользователя (например, «IUser.IUserType»).