[Exercises][C# OOP Advanced] - Reflection - Problem{6} - Mirror Image
Здравейте, колеги,
Бих искал да споделя една интересна (поне за мен) идея за решение на задачата: Магьосникът държи две полета от тип магьосник в себе си - за двете копия, и съответно всеки път като прави заклинание за раздвояване, се създават инстанции за копията. Т.е. магьосникът може да се разгледа като двоично дърво - най-отгоре стои оригиналът, който се разклонява към други две копия, те от своя страна към максимум други две копия и т.н.
private Wizard leftWizardReflection;
private Wizard rightWizardReflection;
При такава структура за изпълнението на заклинанията е достатъчно да се обходи магьосника с рекурсивен Depth-First Search Pre-order алгоритъм. При този алгоритъм рекурсивно се обхожда първо едната част, после другата част на дървото (от някой стартов възел - в случая магьосник). Ето как изглеждат заклинанията:
public void CastReflectionSpell()
{
this.ReflectionSpellCasted?.Invoke(this, EventArgs.Empty);
this.CastReflectionSpell(ref this.leftWizardReflection);
this.CastReflectionSpell(ref this.rightWizardReflection);
}
public void CastFireballSpell()
{
this.FireballSpellCasted?.Invoke(this, EventArgs.Empty);
this.CastFireballSpell(ref this.leftWizardReflection);
this.CastFireballSpell(ref this.rightWizardReflection);
}
ReflectionSpellCasted и FireballSpellCasted са еvent-и, към които можем да се закачим отвън :))) И съответно при всяко извикване от оригиналния магьосник или от някое от копията му - се вдигат event-ите последователно първо по лявото разклонение, после по дясното, така, както се иска в условието на задачата.
Как да избираме обаче точно определено копие на магьосника като начален възел? Тук определено ми куца структурата - аз съм решил проблема със статичен речник <int, Wizard>, който държи срещу id съответния Wizard. Направил съм индексатор, който да връща стойностите от речника:
public Wizard this[int index] => wizardById[index];
Какъв е недостатъка с този подход? Няма да мога да направя друг оригинален магьосник, понеже статичният речник е споделен за всички инстанции на Wizard... Разбира се, специално за тази задача няма значение - имаме нужда само от един оригинален магьосник. Все пак дали можете да предложите идея как да направя достъпа до даден възел (копие на маг), така че да мога да инстанцирам безопасно колкото си искам нови оригинални магьосници?
Ето как изглежда целия клас: Wizard
Благодаря много за отговора и решението. Определено ми даде храна за размисъл. Ако решиш следващата задача 1984, бих те помолил да споделиш решението си - моето стана много грозно, пък и виждам, че има поука от твоя код :)))
Ами и моето решение е грозно, спестих доста код - всякакви фактори-та и 100 реда клас engine, защото направих евента generic, но това доведе до проблем с хоокването на евента и забавяне заради по - сложният reflection. Така, че и ООП-то е кофти и има много излишни неща.
Според мен, се решава с имплементиране на IsPropertyChanged interface от .net, макар да не съм сигурен дали с него може да се избегне хуукването за всяка инстанция на клас или директно се хууква като статичeн евент. Пускането на евентите ще е далеч по-лесно ако не са generic.
Като цяло хинтовете са много оскъдни, трябва бая research, използва се много reflection почти навсякъде, макар, че с анотации трябва да става по-бързо.
Ще се радвам, ако се даде по-нататък едно оптимизирано решение.
Поздрави.