PatternsCSharpExtraAddons/Patterns/Pattern_4-Итератор(Iterator)/Program.cs

334 lines
8.6 KiB
C#
Raw Normal View History

2024-10-05 09:30:14 +03:00
/*
* ПАТТЕРНЫ ПОВЕДЕНИЯ
*
* Глава_4: Итератор
*
* - представляет доступ ко всем элементам составного объекта, не раскрывая его внутреннего представления
*/
/*
* пример техники "перечисляемый-перечислитель"
*/
interface IEnumerable
{
IEnumerator GetEnumenator();
}
class Bank : IEnumerable
{
List<Banknote> bankVault = new List<Banknote>()
{
new Banknote(), new Banknote(),
new Banknote(), new Banknote()
};
public Banknote this[int index]
{
get
{
return bankVault[index];
}
set
{
bankVault.Insert(index, value);
}
}
public int Count { get { return bankVault.Count; } }
public IEnumerator GetEnumenator()
{
return new Cashier(this);
}
}
class Banknote
{
public string Nominal = "100 $";
}
interface IEnumerator
{
bool MoveNext();
void Reset();
object Current { get; }
}
class Cashier : IEnumerator
{
private Bank bank;
private int current = -1;
public Cashier(Bank bank)
{
this.bank = bank;
}
public bool MoveNext()
{
if(current < bank.Count - 1)
{
current++;
return true;
}
return false;
}
public void Reset()
{
current = -1;
}
public object Current
{
get
{
return bank[current];
}
}
}
class SimpleSet<T>
{
int index;//какой именно элемент нужно возвращать
readonly T[] storage;
public SimpleSet(params T[] args)
{
storage = args;
Reset();
}
//свойство возвращающее элеент нашего хранилища
public T Current => storage[index++];
//можно ли продолжать обход массива
public bool MoveNext => index < storage.Length;
//обнуление значение индекса обхода
public void Reset() => index = 0;
}
class SimleSetYeild<T> : IEnumerable<T>// IEnumerator<T>,
{
//int index;
readonly T[] storage;
public SimleSetYeild(params T[] args)
{
storage = args;
//Reset();
}
//public T Current => storage[index++];
//object System.Collections.IEnumerator.Current => Current;
//public void Dispose(){}
public IEnumerator<T> GetEnumerator()
{
var len = storage.Length;
for (int i = 0; i < len; i++)
yield return storage[i]; //позволяет вернуть значение и перейти на следующую итерацию цикла
}
//public bool MoveNext() => index < storage.Length;
//public void Reset() => index = 0;
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => this.GetEnumerator();
}
class Dish : IEnumerable<int>
{
public Dish(string Name, int Weight, int Proteins = 0, int Fats = 0, int Carbohydrates = 0)
{
this.Name = Name;
this.Weight = Weight;
//this.Proteins = Proteins;
//this.Fats = Fats;
nutrients = new Dictionary<string, int>
{
["Proteins"] = Proteins,
["Fats"] = Fats,
["Carbohydrates"] = Carbohydrates
};
}
//допы
readonly Dictionary<string, int> nutrients;
public int Proteins => nutrients[nameof(Proteins)];
public int Fats => nutrients[nameof(Fats)];
public int Carbohydrates => nutrients[nameof(Carbohydrates)];
public double AverageNutrients => nutrients.Values.Average();
//init - только в конструкторе может изменять значения свойства
public string Name { get; init; }
public int Weight { get; init; }
//public int Proteins { get; set; }
//public int Fats { get; set; }
//public int Average => (Proteins + Fats) / 2;
public override string ToString()
{
return $"{nameof(Name)} : {Name} {nameof(Weight)} : {Weight}";
}
public IEnumerator<int> GetEnumerator() => nutrients.Values.GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
}
class Menu : IEnumerable<Dish>
{
public Dish Pizza { get; init; }
public Dish Coffee { get; init; }
public Dish Soup { get; init; }
public IEnumerator<Dish> GetEnumerator()
{
//В каком порядке перечислять
yield return Pizza;
yield return Coffee;
yield return Soup;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => (System.Collections.IEnumerator)this;
}
public class Node<T>
{
public T Value { get; set; }
public Node<T> Left { get; set; }
public Node<T> Right { get; set; }
public Node<T> Parent { get; set; }
public Node (T value) => Value = value;
public Node (T value, Node<T> left = null, Node<T> right = null)
: this(value)
{
Left = left;
Right = right;
if(Left != null) Left.Parent = this;
if(Right != null) Right.Parent = this;
}
public override string ToString() => Value.ToString();
}
//обход самого дерева
public class InOrderIterator<T>
{
public Node<T> Current { get; set; }
private readonly Node<T> root;
private bool detourStarted;
//принимает корневой элемент с которого начнёт обход
public InOrderIterator(Node<T> root)
{
this.root = Current = root;
Reset();
}
public void Reset()
{
Current = root;
while(Current.Left != null) Current = Current.Left;
detourStarted = !true;
}
public bool MoveNext()
{
if (!detourStarted)
{
detourStarted = true;
return true;
}
if (Current.Right != null)
{
Current = Current.Right;
while (Current.Left != null) Current = Current.Left;
return true;
}
else
{
var temp = Current.Parent;
while(temp != null && Current == temp.Right)
{
Current = temp;
temp = temp.Parent;
}
Current = temp;
return Current != null;
}
}
}
class Program
{
public static void Main(string[] args)
{
IEnumerable bank = new Bank();
IEnumerator cashier = bank.GetEnumenator();
while(cashier.MoveNext())
{
if(cashier.Current is Banknote banknote)
Console.WriteLine(banknote.Nominal);
}
//стандартное реализация паттерна Итератор
var array = Enumerable.Range(1, 10).ToArray();
foreach (var item in array)
Console.WriteLine($"array: {item} ");
SimpleSet<int> set = new (array);
set.Reset();
while(set.MoveNext)
Console.WriteLine($"set: {set.Current}");
//Вторая реализация паттерна
SimleSetYeild<int> setyeild = new(array);
foreach (var item in setyeild) Console.WriteLine($"setyeild: {item}");
Menu menu = new()
{
Coffee = new("Latte", 200, 111, 222, 333),
Soup = new("Tom ", 230),
Pizza = new("Margarita", 600),
};
//foreach (var dish in menu) Console.WriteLine(dish);
foreach (var dish in menu)
{
Console.WriteLine($"{dish} - Average: {dish.AverageNutrients} [ ");
foreach (var st in dish)
{
Console.WriteLine($"{nameof(st)} {st}");
}
Console.WriteLine("] ");
}
//пример обхода деревьев (паттерн)
var three = new Node<string>(value: "html",
left: new(value: "head",
left: new(value: "title"),
right: new(value: "meta")),
right: new(value: "body",
left: new(value: "h1",
left: new(value: "a")),
right: new(value: "ul",
left: new(value: "li"),
right: new(value: "li")))
);
var rlr = new InOrderIterator<string>(three);
while (rlr.MoveNext()) Console.WriteLine($"{rlr.Current}");
Console.WriteLine();
rlr.Reset();
while (rlr.MoveNext()) Console.WriteLine($"{rlr.Current}");
}
}