Właśnie oglądałem tę rozmowę przez Grega Younga ostrzegania ludzi całować: Keep It Simple głupie.
Jedną z rzeczy, zasugerował, że aby zrobić programowanie aspektowe, jeden ma nie potrzebują ramy .
Zaczyna od silnego ograniczenia: wszystkie metody przyjmują jeden i tylko jeden parametr (choć nieco później rozluźnia to, stosując częściową aplikację ).
Podaje przykład, aby zdefiniować interfejs:
public interface IConsumes<T>
{
void Consume(T message);
}
Jeśli chcemy wydać polecenie:
public class Command
{
public string SomeInformation;
public int ID;
public override string ToString()
{
return ID + " : " + SomeInformation + Environment.NewLine;
}
}
Polecenie jest realizowane jako:
public class CommandService : IConsumes<Command>
{
private IConsumes<Command> _next;
public CommandService(IConsumes<Command> cmd = null)
{
_next = cmd;
}
public void Consume(Command message)
{
Console.WriteLine("Command complete!");
if (_next != null)
_next.Consume(message);
}
}
Aby zalogować się do konsoli, wystarczy zaimplementować:
public class Logger<T> : IConsumes<T>
{
private readonly IConsumes<T> _next;
public Logger(IConsumes<T> next)
{
_next = next;
}
public void Consume(T message)
{
Log(message);
if (_next != null)
_next.Consume(message);
}
private void Log(T message)
{
Console.WriteLine(message);
}
}
Następnie rejestrowanie przed komendą, obsługa komend i rejestrowanie po komendach są następujące:
var log1 = new Logger<Command>(null);
var svr = new CommandService(log);
var startOfChain = new Logger<Command>(svr);
a polecenie jest wykonywane przez:
var cmd = new Command();
startOfChain.Consume(cmd);
Aby to zrobić na przykład w PostSharp , należy opisać w CommandService
następujący sposób:
public class CommandService : IConsumes<Command>
{
[Trace]
public void Consume(Command message)
{
Console.WriteLine("Command complete!");
}
}
A potem trzeba zaimplementować rejestrowanie w klasie atrybutów, takiej jak:
[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine(args.Method.Name + " : Entered!" );
}
public override void OnSuccess( MethodExecutionArgs args )
{
Console.WriteLine(args.Method.Name + " : Exited!" );
}
public override void OnException( MethodExecutionArgs args )
{
Console.WriteLine(args.Method.Name + " : EX : " + args.Exception.Message );
}
}
Argument, który wykorzystuje Greg, jest taki, że połączenie atrybutu z implementacją atrybutu to „zbyt dużo magii”, aby móc wyjaśnić, co dzieje się z młodszym programistą. Początkowy przykład to „tylko kod” i można go łatwo wyjaśnić.
Tak więc po tym dość długotrwałym narastaniu pojawia się pytanie: kiedy przejdziesz z nieszkieletowego podejścia Grega do używania czegoś takiego jak PostSharp dla AOP?
źródło
IConsumes
elementy. Zamiast korzystać z zewnętrznego XML lub jakiegoś płynnego interfejsu --- jeszcze jedna rzecz do nauczenia się. Można argumentować, że ta metodologia to także „kolejna rzecz do nauczenia się”.Odpowiedzi:
Czy on próbuje napisać strukturę AOP „prosto do TDWTF”? Poważnie wciąż nie mam pojęcia, o co mu chodziło. Jak tylko powiesz „Wszystkie metody muszą przyjąć dokładnie jeden parametr”, to nie udało ci się, prawda? Na tym etapie mówisz: OK, to nakłada pewne poważne sztuczne ograniczenia na moją zdolność do pisania oprogramowania, zostawmy to teraz przedtem, trzy miesiące później mamy pełną koszmarną bazę kodu do pracy.
I wiesz co? Za pomocą Mono.Cecil możesz dość łatwo napisać prostą strukturę rejestrowania opartą na IL opartą na IL . (testowanie jest nieco bardziej skomplikowane, ale ...)
Aha i IMO, jeśli nie używasz atrybutów, to nie jest AOP. Cały sens wprowadzania kodu wejścia / wyjścia metody rejestrowania na etapie postprocesora polega na tym, że nie powoduje on bałaganu w plikach kodu i nie trzeba się nad tym zastanawiać, zmieniając kod; taka jest jego moc.
Wszystko, co Greg pokazał, to głupi, głupi paradygmat.
źródło
let concat (x : string) y = x + y;; concat "Hello, " "World!";;
wygląda na to, że potrzeba dwóch argumentów, czego mi brakuje?concat "Hello, "
tworzysz funkcję, która jest sprawiedliway
ix
wstępnie zdefiniowana jako lokalne powiązanie na „Cześć”. Gdyby można było zobaczyć tę funkcję pośrednią, wyglądałaby ona jaklet concat_x y = "Hello, " + y
. A potem dzwoniszconcat_x "World!"
. Składnia czyni to mniej oczywistym, ale pozwala to „upiec” nowe funkcje - na przykładlet printstrln = print "%s\n" ;; printstrln "woof"
. Ponadto, nawet jeśli robisz coś takiegolet f(x,y) = x + y
, to tak naprawdę tylko jeden argument krotki .Mój Boże, ten facet jest nie do zniesienia. Chciałbym po prostu przeczytać kod z twojego pytania zamiast oglądać tę rozmowę.
Nie sądzę, żebym kiedykolwiek użył tego podejścia, gdyby tylko ze względu na użycie AOP. Greg mówi, że nadaje się do prostych sytuacji. Oto, co zrobiłbym w prostej sytuacji:
Tak, zrobiłem to, całkowicie pozbyłem się AOP! Czemu? Ponieważ nie potrzebujesz AOP w prostych sytuacjach .
Z punktu widzenia programowania funkcjonalnego, dopuszczenie tylko jednego parametru na funkcję tak naprawdę mnie nie przeraża. Niemniej jednak, to naprawdę nie jest projekt, który działa dobrze w C # - i sprzeczanie się z ziarnami twojego języka niczego nie całuje.
Użyłbym tego podejścia tylko wtedy, gdyby konieczne było stworzenie modelu poleceń na początek, na przykład gdybym potrzebował stosu cofania lub gdybym pracował z poleceniami WPF .
W przeciwnym razie użyłbym ramy lub refleksji. PostSharp działa nawet w Silverlight i Compact Framework - więc to, co nazywa „magia” naprawdę nie jest magiczne w ogóle .
Nie zgadzam się również z unikaniem ram, aby móc wyjaśnić rzeczy młodym. To im nie pomaga. Jeśli Greg traktuje swoich juniorów tak, jak sugeruje, by byli traktowani jak idioci z grubymi czaszkami, to podejrzewam, że jego starsi programiści też nie są wspaniali, ponieważ prawdopodobnie nie mieli oni okazji dowiedzieć się czegoś podczas ich młodsze lata.
źródło
Zrobiłem niezależne badanie na studiach na temat AOP. Właściwie napisałem artykuł na temat podejścia do modelowania AOP z wtyczką Eclipse. To chyba trochę nieistotne. Kluczowe punkty to: 1) byłem młody i niedoświadczony oraz 2) pracowałem z AspectJ. Mogę powiedzieć, że „magia” większości platform AOP nie jest tak skomplikowana. Właściwie pracowałem nad projektem mniej więcej w tym samym czasie, w którym próbowałem zastosować podejście jednoparametrowe za pomocą tablicy hashtable. IMO, podejście jednoparametrowe jest naprawdę strukturą i jest inwazyjne. Nawet w tym poście spędziłem więcej czasu próbując zrozumieć podejście jednoparametrowe niż przeglądając podejście deklaratywne. Dodam zastrzeżenie, że nie oglądałem filmu, więc „magią” tego podejścia może być zastosowanie częściowych aplikacji.
Myślę, że Greg odpowiedział na twoje pytanie. Powinieneś przejść na to podejście, jeśli uważasz, że znajdujesz się w sytuacji, w której spędzasz zbyt dużo czasu na wyjaśnianiu struktur AOP młodszym programistom. IMO, jeśli jesteś na tej łodzi, prawdopodobnie zatrudniasz niewłaściwych młodszych programistów. Nie sądzę, aby AOP wymagało deklaratywnego podejścia, ale dla mnie jest to po prostu o wiele bardziej jasne i nieinwazyjne z punktu widzenia projektowania.
źródło
IConsume<T>
przykład jest zbyt skomplikowany z punktu widzenia tego, co zostało osiągnięte.O ile mi czegoś brakuje, kod, który pokazałeś, jest wzorcem projektowym „łańcucha odpowiedzialności”, który jest świetny, jeśli potrzebujesz połączyć szereg działań na obiekcie (takich jak polecenia przechodzące przez szereg programów obsługi poleceń) w środowisko uruchomieniowe.
AOP korzystający z PostSharp jest dobry, jeśli wiesz w czasie kompilacji, jakie zachowanie chcesz dodać. Tkanie kodu PostSharp praktycznie oznacza, że nie ma narzutu w czasie wykonywania i rzeczywiście utrzymuje kod w czystości (zwłaszcza, gdy zaczynasz używać rzeczy takich jak aspekty multiemisji). Nie sądzę, że podstawowe użycie PostSharp jest szczególnie skomplikowane do wyjaśnienia. Minusem PostSharp jest to, że znacząco skraca czas kompilacji.
Używam obu technik w kodzie produkcyjnym i chociaż istnieje pewne nakładanie się ich zastosowania, myślę, że w większości dotyczyły one różnych scenariuszy.
źródło
Jeśli chodzi o jego alternatywę - byłem tam, zrobiłem to. Nic nie jest porównywalne z czytelnością atrybutu jednowierszowego.
Wyprowadź krótkiego wykładu nowym chłopakom, wyjaśniając im, jak działają rzeczy w AOP.
źródło
To, co opisuje Greg, jest absolutnie uzasadnione. I jest w tym także piękno. Ta koncepcja ma zastosowanie w innym paradygmacie niż orientacja czysto obiektowa. To bardziej podejście proceduralne lub podejście projektowe zorientowane na przepływ. Tak więc, jeśli pracujesz ze starszym kodem, zastosowanie tej koncepcji będzie dość trudne, ponieważ może być konieczne dużo refaktoryzacji.
Spróbuję podać inny przykład. Może nie jest idealny, ale mam nadzieję, że to wyjaśnia sprawę.
Mamy więc usługę produktu, która korzysta z repozytorium (w tym przypadku użyjemy kodu pośredniczącego). Usługa otrzyma listę produktów.
Oczywiście możesz również przekazać interfejs do usługi.
Następnie chcemy wyświetlić listę produktów w widoku. Dlatego potrzebujemy interfejsu
oraz polecenie, które przechowuje listę produktów
i widok
Teraz potrzebujemy kodu, który wykonuje to wszystko. Zrobimy to w klasie o nazwie Aplikacja. Metoda Run () jest metodą integrującą, która nie zawiera logiki biznesowej lub jest w niej bardzo mało. Zależności są wprowadzane do konstruktora jako metody.
Na koniec tworzymy aplikację w głównej metodzie.
Fajną rzeczą jest to, że możemy dodawać takie aspekty, jak rejestrowanie lub obsługa wyjątków bez dotykania istniejącego kodu i bez ram lub adnotacji. Do obsługi wyjątków np. Dodajemy nową klasę:
A następnie łączymy to razem podczas komponowania w punkcie wejścia aplikacji. nie musimy nawet dotykać kodu w klasie Application. Po prostu zastępujemy jedną linię:
Aby wznowić: Gdy mamy projekt zorientowany na przepływ, możemy dodać aspekty, dodając funkcjonalność w nowej klasie. Następnie musimy zmienić jedną linię w metodzie kompozycji i to wszystko.
Myślę więc, że odpowiedź na twoje pytanie brzmi: nie możesz łatwo przejść z jednego podejścia do drugiego, ale musisz zdecydować, jakie podejście architektoniczne zastosujesz w swoim projekcie.
edycja: Właściwie właśnie zdałem sobie sprawę, że częściowy wzorzec aplikacji użyty z usługą produktu czyni sprawy nieco bardziej skomplikowanymi. Musimy owinąć kolejną klasę wokół metody obsługi produktu, aby również tutaj dodać aspekty. Może to być coś takiego:
Następnie należy zmienić skład w następujący sposób:
źródło