Немного сложно понять, что предложить, без лучшего понимания кода ... но некоторые вещи, которые работали для меня в подобных ситуациях, включают:
- Используйте Стратегию для дублированного кода. У меня был самый большой успех, когда стратегия заключалась в классе, реализующем известный интерфейс (один класс на альтернативную стратегию). Часто в таких случаях я использую некую форму структуры внедрения зависимостей (обычно StructureMap) для передачи соответствующей стратегии / стратегий классу.
- Использовать некоторый класс шаблонов (или методы шаблонов) для общих элементов.
- Используйте Декоратор , чтобы добавить определенные функции для некоторых основных клиентов.
STW предложил мне кое-что прояснить, что я имею в виду под «Стратегией» и чем это отличается от обычного наследования. Я предполагаю, что наследование - это то, с чем вы очень хорошо знакомы - что-то (обычно это метод - abstract
или virtual
) в базовом классе заменяется альтернативной реализацией в производном классе.
Стратегия (по крайней мере, как я обычно ее использую) обычно реализуется совершенно другим классом. Часто все, что будет содержать этот класс, - это реализация для одной заменяемой операции. Например, если «операция» заключается в выполнении некоторой проверки, у вас может быть NullValidationStrategy
, который ничего не делает, и ParanoidValidationStrategy
, который гарантирует, что каждый McGuffin имеет правильную высоту, ширину и определенный оттенок синего. Причина, по которой я обычно реализую каждую стратегию в своем собственном классе, заключается в том, что я стараюсь следовать принципу единственной ответственности , который может упростить повторное использование кода позже.
Как я упоминал выше, я обычно использую инфраструктуру Dependency Injection (DI), чтобы «внедрить» соответствующую стратегию через конструктор класса, но аналогичные результаты могут быть получены с помощью других механизмов - например, имеющий SetSomeOperationStrategy(ISomeOperation StrategyToUse)
метод или свойство, которое содержит ссылку на стратегию. Если вы не используете DI, и стратегия всегда будет одинаковой для данного типа клиента, вы всегда можете установить правильный выбор при создании класса. Если стратегия не будет одинаковой для каждого экземпляра данного типа клиента, то вам, вероятно, нужен какой-то клиент фабрика (часто достаточно фабричный метод ).