Niedawno podczas koleżeńskiej konserwacji wypłynął nam temat pantoflarstwa, czyli bezwarunkowej podległości osobnika płci męskiej pod swego żeńskiego w życiu partnera. Swoją Panią.
I nieuchronnie już wówczas do głowy napłynęła mi myśl, jak taką sytuację można doskonale zamodelować przy użyciu PostSharp – godnego uwagi darmowego narzędzia do programowania aspektowego w .NET. Przysiadłem na chwilę, ściągnąłem Post#, zaimplementowałem minidemko i je niniejszym prezentuję:
Zaczynamy od naszego MĘŻCZYZNY, który robić może co chce i dumny jest z tego że ŁO-HO-HO:
1: public class Man
2: {
3: public void DrinkBeer()
4: {
5: Console.WriteLine("Drinking beer, yummy!");
6: }
7:
8: public void BuyFlowers()
9: {
10: Console.WriteLine("Giving flowers for my valentine...");
11: }
12:
13: public void WatchTv()
14: {
15: Console.WriteLine("Relaxing with tv.");
16: }
17: }
Stwórzmy takiego kola i zobaczmy jak mu życie płynie:
1: static void Main(string[] args)
2: {
3: Man freeMan = new Man();
4:
5: freeMan.DrinkBeer();
6: Console.WriteLine("------------------");
7: freeMan.BuyFlowers();
8: Console.WriteLine("------------------");
9: freeMan.WatchTv();
10: }
Skutek:
Taa...
Dodajmy jednak łyżkę dziegciu do tej beczki miodu, przerysowując nieco rzeczywistość przy pomocy postsharpowego atrybutu:
1: [Serializable, MulticastAttributeUsage(MulticastTargets.Method)]
2: public class PantofelAttribute : OnMethodBoundaryAspect
3: {
4: private readonly Girlfriend _girlfriend = new Girlfriend();
5:
6: public override void OnEntry(MethodExecutionEventArgs eventArgs)
7: {
8: var actionName = eventArgs.Method.Name;
9: try
10: {
11: _girlfriend.ConsiderPermission(actionName);
12: }
13: catch (Exception exc)
14: {
15: Console.WriteLine(
16: @"Sorry, permission for {0} was not granted.
17: {1} was thrown with the following message from your dearest beloveth:
18: ""{2}""",
19: actionName, exc.GetType().Name, exc.Message);
20:
21: eventArgs.FlowBehavior = FlowBehavior.Return;
22: }
23: }
24: }
Jak to bywa – przed wykonaniem jakiejkolwiek akcji będzie teraz biedak musiał o pozwolenie swojej białogłowy się starać. A że w takiej sytuacji logika zbyt skomplikowana nie jest, i ją można zamodelować bez większego kłopotu:
1: [Serializable]
2: public class Girlfriend
3: {
4: public void ConsiderPermission(string actionName)
5: {
6:
7: if (actionName.Contains("Beer"))
8: {
9: throw new Foch("You've got to be kidding me!");
10: }
11:
12:
13: if (actionName.Contains("Flowers"))
14: return;
15:
16:
17: throw new IDontThinkSoException("Not really sure, but better not.");
18: }
19: }
Można zauważyć, że do sterowania przepływem użyłem w tym przypadku wyjątków, co nie jest praktyką zalecaną. Doświadczeni przyznać jednak mogą rację, że zwykłe zwrócenie true/false mogłoby nie oddać realizmu sytuacji w wystarczającym stopniu :).
No dobra, zmodyfikujmy lekko naszego cwaniaczka:
1: [Pantofel]
2: public class Man
3: {
i zobaczmy jak jego poczynania będą wyglądały teraz:
I cóż, nic dodać, nic ująć...
A jak to jest czytelniku u ciebie? Nałożono ci ów atrybut z bezlitosną konsekwencją, czy też może zmodyfikowałeś go lekko przekazując w konstruktorze enum ObedienceLevel starając się w miarę możliwości ustawiać jakąś akceptowalną wartość?:)