PatternsCSharpProgramming/Patterns/Strategy/Program.cs

218 lines
7.2 KiB
C#
Raw Normal View History

2024-10-05 09:15:54 +03:00
/* Стратегия
Определяет группу алгоритмов,
инкапсулирует их и делает взаимозаменяемыми.
Позволяет изменять алгоритм независимо от клиентов,
его использующих.
*/
/*
* На чем строилось:
* СЕРГЕЙ ТЕПЛЯКОВ - Паттерны проектирования на платформе .Net
* ШЕВЧУК, АХРИМЕНКО, КАСЬЯНОВ - Приемы объектно-ориентированного проектирования
*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
* Паттерн 1: Стратегия
*
* - является более контекстно зависимой операцией
*
* Причины применения:
* 1.необходимость инкапсуляции поведения или алгоритма
* 2.необходимость замены поведения или алгоритма во время исполнения
*
* Другими словами, стратегия обеспечивает точку расширения системы
* в определенной плоскости: класс-контекст (LogProcessor) принимает экземпляр стратегии (LogFileReader)
* и не знает, какой вариант стратегии он собирается использовать.
*
* Особенность:
* Передача интерфейса ILogReader классу LogProcessor увеличивает гибкость,
* но в то же время повышает сложность.
* Теперь клиентам класса LogProcessor нужно решить, какую реализацию использовать,
* или переложить эту ответственность на вызывающий код.
*/
/*
* ВМЕСТО
* классической стратегии на основе наследования
* можно использовать стратегию на основе делегатов
*
* ПРИМЕР: Стратегия сортировки
*/
/*
* ВАЖНО: Гибкость не бывает бесплатной, поэтому выделять стратегии стоит тогда,
* когда действительно нужна замена поведения во время исполнения.
*/
using Strategy;
class Program
{
#region Пример 3 - Сomparer
public static void SortListId(List<Employee> list)
{
list.Sort(new EmployeeByIdComparer()); //используем функтор
}
public static void SortListName(List<Employee> list)
{
list.Sort((x, y) => x.Name.CompareTo(y.Name)); //используем делегат
}
#endregion
public static void Main(string[] args)
{
#region Пример 1 - базовое
var car = new Car(new PetrolMove());
car.Move();
car.Movable = new ElectronicMove();
car.Move();
Console.ReadKey();
#endregion
#region Пример 2 - ILogReader
LogFileReader logFileReader = new LogFileReader();
//создали делегат который принимает в себя метод,
//в результате выполнения которого возвращается List<LogEntry>
Func<List<LogEntry>> _import = () => logFileReader.Read();
LogProcessor processor = new LogProcessor(_import);
processor.ProcessLogs();
#endregion
#region Пример 3 - Сomparer
List<Employee> employees = new List<Employee>
{
new Employee
{
Id = 8,
Name = "asmus"
},
new Employee
{
Id = 1,
Name = "robin"
},
new Employee
{
Id = 2,
Name = "satan"
},
new Employee
{
Id = 5,
Name = "dastin"
}
};
SortListId(employees); //отсортировали по id через функтор
SortListName(employees); //отсортировали по Name через делегат
Console.WriteLine();
var comparer = new EmployeeByIdComparer();
var set = new SortedSet<Employee>(comparer); //конструктор принимает IComparable
//нет конструктора, принимающего делегат Comparison<T>
//можно создать небольшой адаптерный фабричный класс
var comparer_factory = ComparerFactory.Create<Employee>((x, y) => x.Id.CompareTo(y.Id));
//он помещает сюда фабрику
var set_factory = new SortedSet<Employee>(comparer_factory);
#endregion
}
}
/// <summary>
/// Поведение движения
/// </summary>
interface IMovable
{
void Move();
}
/// <summary>
/// Бензиновый двигатель
/// </summary>
class PetrolMove : IMovable
{
public void Move()
{
Console.WriteLine("Движение на бензине");
}
}
/// <summary>
/// Электродвигатель
/// </summary>
class ElectronicMove : IMovable
{
public void Move()
{
Console.WriteLine("Движение на электричестве");
}
}
/// <summary>
/// Автомобиль
/// </summary>
class Car
{
/// <summary>
/// Cпособ передвижения автомобиля
/// </summary>
public IMovable Movable { private get; set; }
public Car(IMovable movable)
{
Movable = movable;
}
public void Move()
{
Movable.Move();
}
}
class Employee
{
public int Id { get; set; }
public string? Name { get; set; }
public override string ToString()
{
return string.Format($"ID={Id}, Name={Name}");
}
}
/// <summary>
/// Реализует интерфейс сортировки
/// Добавлет возможность сортировки по ID по возрастающей
/// </summary>
class EmployeeByIdComparer : IComparer<Employee>
{
int IComparer<Employee>.Compare(Employee? x, Employee? y)
{
if (x is Employee xx && y is Employee yy)
return xx.Id.CompareTo(yy.Id);
else
return 0;
}
}
/// <summary>
/// Фабричный шаблон для создания экземпляров IComparer
/// </summary>
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)
{
if (x == null || y == null)
return 0;
return _comparer(x, y);
}
}
}