334 lines
8.6 KiB
C#
334 lines
8.6 KiB
C#
/*
|
||
* ПАТТЕРНЫ ПОВЕДЕНИЯ
|
||
*
|
||
* Глава_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}");
|
||
}
|
||
}
|
||
|