#c_sharp #ооп #шаблоны_проектирования
Хотелось бы узнать о том, как данный паттерн может быть реализован, но не по "стандартной" схеме, предложенной GOF. Привожу пример "стандартной" реализации. class Component { Component() { ... } } class ConcreteComponent : Component { ConcreteComponent() { ... } } class Decorator : Component { Component c; int newState; public void SetComponent(Component component) { ... } Decorator() { ... } } Можно ли декорировать объекты как-то по другому, не совмещая агрегацию и наследование, но чтобы при этом сохранялись все преимущества паттерна? Желательно на C#.
Ответы
Ответ 1
Я обычно использую декораторы вместе с интерфейсом и композицией. Например, есть некоторый источник данных о погоде: public interface IWeatherProvider { public WeatherInfo GetWeather(string city); } Есть реализация по умолчанию. Например, она ходит по http к провайдеру данных: public class DefaultWeatherProvider : IWeatherProvider { public WeatherInfo GetWeather(string city) { // обращение по HTTP } } В некоторых сценариях нам необязательно запрашивать погоду каждый раз у провайдера, а достаточно кэшировать ее: public class CachingWeatherProvider : IWeatherProvider { private readonly Dictionary_cache; private readonly IWeatherProvider _provider; public CachingWeatherProvider(IWeatherProvider provider) { _provider = provider; _cache = new Dictionary (); } public WeatherInfo GetWeather(string city) { WeatherInfo weather; if (!_cache.TryGetValue(city, out weather)) { weather = _provider.GetWeather(city); _cache[city] = weather; } return weather; } } Используем: var provider = new CachingWeatherProvider(new DefaultWeatherProvider()); Или вдруг источник ненадежный, часто лежит, и вы захотели добавить ретрай: public class RetryingWeatherProvider : IWeatherProvider { private readonly IWeatherProvider _provider; private int _maxRetries; public RetryingWeatherProvider(IWeatherProvider provider, int maxRetries) { _provider = provider; _maxRetries = maxRetries; } public WeatherInfo GetWeather(string city) { int retry = 0; do { try { return _provider.GetWeather(city); } catch (WebException) { if (retry == _maxRetries) { throw; } else { // подождем немного } } } while (++retry < _maxRetries) } } И тогда можно наворотить провайдер с кэшем и ретраем: var provider = new CachingWeatherProvider( new RetryingWeatherProvider(new DefaultWeatherProvider(), 3)); Как именно реализуется декоратор в принципе неважно, отличия имеют право на жизнь. Важно лишь помнить про open-closed принцип: декоратор очень полезен, когда вам нужно расширить функциональность кода, не трогая при этом основной код. У вас есть провайдер данных. Чтобы добавить функциональность ретрая, вы не лезете в основной провайдер, а создаете декоратор. Чтобы добавить кэширование, вы опять же не лезете в провайдер, а создаете еще один декоратор и т.д. P.S. Весь приведенный код не production ready, а только иллюстрация.
Комментариев нет:
Отправить комментарий