Паттерны проектирования
1. Паттерн «Стратегия» (Strategy). Окончание
Интерфейс vs. Делегат
Поскольку некоторые стратегии содержат лишь один метод, в .Net часто вместо классической стратегии на основе наследования можно использовать стратегию на основе делегатов. Иногда эти подходы совмещаются, что позволяет использовать наиболее удобный вариант.
Классическим примером такой ситуации является стратегия сортировки, представленная интерфейсом
IComparable<T> и делегатом Comparison<T>:class Employee {
public int Id { get; set; }
public string Name { get; set; }
…
}
// функтор, реализующий интерфейс
class EmployeeByIdComparer : IComparer<Employee> {
public int Compare(Employee x, Employee y) {
return x.Id.CompareTo(y.Id);
}
}
// используем функтор
list.Sort(new EmployeeByIdComparer());
// используем делегат
list.Sort((x, y) => x.Name.CompareTo(y.Name));
По сравнению с использованием лямбда-выражений, реализация интерфейса требует больше кода и приводит к переключению контекста при чтении (необходимости посмотреть реализацию функтора). При использовании метода List.Sort есть возможность использовать оба варианта, но так бывает не всегда, например в случае с классами SortedList или SortedSet:var comparer = new EmployeeByIdComparer();В этом случае можно создать небольшой адаптерный фабричный класс, который будет принимать делегат
// Конструктор принимает IComparable
var set = new SortedSet<Employee>(comparer);
// Нет конструктора, принимающего делегат Comparison<T>
Comparison<T> и возвращать интерфейс IComparable<T>:class ComparerFactory {
public static IComparer<T> Create<T>(Comparison<T> comparer) {
return new DelegateComparer<T>(comparer);
}
private class DelegateComparer<T> : IComparer<T> {
private readonly Comparison<T> _comparer;
public DelegateComparer(Comparison<T> comparer) {
_comparer = comparer;
}
public int Compare(T x, T y) {
return _comparer(x, y);
}
}
}
Теперь, используя этот класс, можно создать функтор из лямбда-делегата: var comparer = ComparerFactory.Create<Employee>((x, y) => x.Id.CompareTo(y.Id));Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 1.
var set = new SortedSet<Employee>(comparer);