zip sa izvornim kodom sa GitHuba · C#, 2013
Izvorni kod na GitHubu
C# struktura za upravljanje procesima. Napisana 2013. godine; prevedena sa originalne ruske stranice.
Color. Ili uzmi ColorTemplate<T> i preskoči ceremoniju.SimpleGraphNode<T>, uz prepisan Stop i, po potrebi, Undo. Ako proces mora da radi nešto neobično sa ulaznim bojama, nasledi GraphNode i prepiši Work u celosti.OutPoint i SerialOutPoint primaju početnu boju u konstruktoru.ConnectTo.new, prosleđujući konstruktoru čvorove čije te krajnje vrednosti zanimaju. Ako prosledeš čvor koji nije prvi, svaki čvor pre njega dobiće Undo signal.OnFinish obrađivače na grafu, ili na bilo kom njegovom čvoru, da obradiš rezultate.Start ili StartAsync.Graf boja je usmereni aciklični graf čiji su čvorovi procesi. Svaki čvor i svaka grana mogu da se oboje, i svakom čvoru i grani može da se pošalje signal.
Boja su podaci određenog tipa koji putuju između čvorova. Signal su podaci određenog tipa koji putuju granama u suprotnom smeru. Grana je objekat koji spaja dva čvora i ima pozitivnu dužinu.
Graf poštuje nekoliko pravila:
Iz ovih aksioma sledi nekoliko vrsta čvorova koji se različito odnose prema boji i signalima. Kad se neke vrste povežu međusobno, suvišne grane se odbacuju da se uštede resursi.
InPoint)
InPoint): kako se boji.Ulazna tačka je čvor sa više ulaznih grana i tačno jednom izlaznom. Da bi se uštedeli resursi i logika ostala jednostavna, izlazna grana se odbacuje i ulazna tačka se kači direktno na sledeći čvor (njen Parent). Čim je bilo koja ulazna grana obojena, ulazna tačka uzima njenu boju. Svaki signal koji ulazna tačka primi odmah šalje u sve ulazne grane.
OutPoint)
OutPoint): kako se boji.Izlazna tačka ima jednu ulaznu granu i više izlaznih. Čim se oboji, boje se sve izlazne grane. Na serijski signal sa jedne izlazne grane čeka dok sve ostale ne signaliziraju, pa šalje AllPosibilitiesFailedException sa greškama svake grane redom kako su stigle, tako da je prva greška na čelu liste.
Izlazne tačke šalju jednu boju u više pravaca odjednom. Zakači jednu na čvor „sačuvaj kao JPEG“ i na čvor za bekap, i jedan niz fotografija se čuva kao JPEG i bekapuje paralelno, u odvojenim nitima. Ako više čvorova treba istu boju, koristi jednu izlaznu tačku, a ne više njih sa istim podacima. Samo imaj na umu da tačka čuva ceo lanac grešaka sa svih svojih grana, pa ako treba da pratiš greške u jednoj konkretnoj grani, zakači je samo na tu granu, jel da.
SerialOutPoint)
SerialOutPoint): kako se boji.Serijska izlazna tačka boji izlazne grane jednu po jednu i čeka da svaka završi. Prva se boji najkraća grana i postaje tekuća; čvor čeka njen signal. Na signal o grešci najkraća neobojena grana postaje tekuća, boji se, i čekanje kreće ispočetka. Signali sa bilo koje grane osim tekuće se ignorišu.
Čemu služe serijske izlazne tačke? Uglavnom lancima u kojima unapred ne znaš koji od više sličnih čvorova može da obavi posao. Recimo, treba da konvertuješ video sa zadatim parametrima, imaš više konvertera, svaki podržava druge formate, i ne možeš unapred da znaš koji će uspeti. Pošalji parametre konverzije i ime fajla serijskoj izlaznoj tački, na svaki izlaz zakači konverter, a izlaze svih konvertera spoji u jednu ulaznu tačku. Serijska tačka pokreće prvi konverter; ako on padne, drugi, i tako dalje, dok neki ne konvertuje fajl i ne preda ga zajedničkoj ulaznoj tački. Neiskorišćeni konverteri se gase bojenjem u crno. Ako nešto pukne dalje niz lanac, serijska tačka vraća i tu grešku.
WorkNode)
GraphNode): kako se boji.Na radni čvor je zakačeno više ulaznih tačaka i jedna izlazna. On pretvara ulazne boje algoritmom koji piše programer. Čeka dok se svaka ulazna tačka bez izuzetka ne oboji, pretvara njihove boje i boji sebe rezultatom. Ako rezultat ne može da se dobije, čvor šalje signal o grešci i boji sebe u crno. Svaki primljeni signal odmah prosleđuje dalje uz stablo. Pretvaranje, zaustavljanje i poništavanje (Work, Stop, Undo) garantovano se izvršavaju u posebnoj niti.
Da bi se graf pokrenuo sa Start ili StartAsync, navodiš njegove ključne čvorove. Kad svi oni prime serijski signal, izvršavanje je gotovo. Putanje se prate samo za te čvorove i samo oni daju rezultat grafa (GraphResult).
Pre pokretanja, svi mogući poslednji čvorovi i viseće grane skupljaju se u listu Last. Za svaki od njih, svaki početni čvor i grana koji mogu da dovedu do njega idu u listu First, a boje svih prvih objekata čuvaju se posebno. Graf je spreman. Ima četiri glavna metoda: Stop, Clear, Start, Undo.
Stop šalje Stop signal u sve poslednje objekte i čeka da stigne do svih prvih. Svaki čvor prestaje da radi.Clear se zove na zaustavljenom grafu. Šalje crno u sve prve objekte i čeka da crno stigne do svih poslednjih čvorova. Graf je potpuno očišćen; svaki objekat je crn.Start se zove na očišćenom grafu. Svi prvi objekti se boje sačuvanim prvim bojama i graf čeka da svi ključni objekti navedeni pri stvaranju signaliziraju.Undo šalje broadcast Undo u sve poslednje čvorove i čeka da stigne do prvih. Svaki objekat koji implementira IUndoable i nije označen sa AlreadyUndone uklanja rezultate svog rada (privremene fajlove i slično).Kad svi ključni čvorovi signaliziraju, pokreće se Finish i nalazi najduže putanje kojima je boja prošla od ključnih objekata. Zašto najduže? U teoriji je to najduži lanac pretvaranja bez greške. Nazad na primer sa videom: svaku video traku treba izvući u poseban fajl, konvertovati i spojiti sa ostalim trakama. Ako usput ništa nije puklo, izvršavanje se završava lancem „traka → fajl nekonvertovane trake → fajl konvertovane trake → spojeni fajl sa više traka“, i taj lanac možeš da obradiš kako hoćeš, na primer da obrišeš sve privremene fajlove. Ako je neka faza pukla, dobijaš deo lanca do mesta greške i možeš, recimo, da zadržiš privremene fajlove i kažeš korisniku da spajanje nije uspelo, ali da je izvlačenje trake prošlo. Ako graf ima izlazne tačke, dužine njihovih grana podešavaju dužinu konačne putanje.
Kad su najduže putanje nađene, svaki objekat van njih dobija Undo signal, pa čvor koji je napravio privremeni fajl briše ga. Kad je izvršavanje gotovo i putanje nađene, okida se OnFinish.
Boja je klasa nasleđena od Color. To bi, naravno, bilo previše jednostavno, jer boje mogu da se mešaju. Color je element povezane liste, cela lista opisuje mešavinu boja, a bilo koji element potpuno određuje listu. Tako da kad objekat grafa primi boju, zapravo prima mešavinu, koju možeš da raspakuješ sa Color.Demix(). Mešavina se pravi statičkim Color.Mix().
Zašto zavaravati programera običnim Color kad bi ColorMix sve rekao sam? Zato što mešavine postoje uglavnom za debagovanje: možeš da umešaš debag informacije u pravi rezultat funkcije i izvučeš ih nazad sa Demix, dok sledeći čvor vidi običnu boju bez dodataka. Ako boja prođe filter po tipu, čvor je prihvata kao „dobru“ i radi s njom ne primećujući primese. Svaka boja može da se tretira i kao jedna nijansa i kao mešavina, zavisno od toga šta rade funkcije čvora.
Dobra praksa: koristi mešavine samo za debagovanje i napravi posebnu boju za svaki tip podataka koji funkcije tvog čvora koriste. Ako čvor prima string, logičku vrednost i niz brojeva neograničene dužine, daj mu dva nevidljiva ulaza za string i logičku vrednost, izložena kao svojstva, a čvor proglasi za onaj koji prima brojeve. Onda svi brojevi stižu kao „dobre“ boje, dok string i logička vrednost sede na nevidljivim ulazima.