Я просто смотрел этот разговор по Greg Молодых предупреждений людей к ПОЦЕЛУЮ: Keep It Simple Stupid.
Одна из вещей , которые он предложил, что делать аспектно-ориентированное программирование, один вовсе не нужны рамки .
Он начинает с строгого ограничения: все методы принимают один и только один параметр (хотя он ослабляет это чуть позже, используя частичное применение ).
Пример, который он приводит, - определить интерфейс:
public interface IConsumes<T>
{
void Consume(T message);
}
Если мы хотим выполнить команду:
public class Command
{
public string SomeInformation;
public int ID;
public override string ToString()
{
return ID + " : " + SomeInformation + Environment.NewLine;
}
}
Команда реализована так:
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);
}
}
Чтобы войти в консоль, нужно просто выполнить:
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);
}
}
Затем ведение журнала перед командой, служба команд и запись после команды просто:
var log1 = new Logger<Command>(null);
var svr = new CommandService(log);
var startOfChain = new Logger<Command>(svr);
и команда выполняется:
var cmd = new Command();
startOfChain.Consume(cmd);
Чтобы сделать это, например, в PostSharp , можно аннотировать CommandService
так:
public class CommandService : IConsumes<Command>
{
[Trace]
public void Consume(Command message)
{
Console.WriteLine("Command complete!");
}
}
И тогда придется реализовать запись в класс атрибута что-то вроде:
[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 );
}
}
Аргумент, который использует Грег, заключается в том, что связь между атрибутом и реализацией атрибута «слишком большая магия», чтобы можно было объяснить, что происходит с младшим разработчиком. Начальный пример - это просто код и его легко объяснить.
Итак, после этого довольно затянувшегося процесса создания возникает вопрос: когда вы переключаетесь с неструктурного подхода Грега на использование чего-то вроде PostSharp для AOP?
источник
IConsumes
части. Вместо того, чтобы использовать внешний XML или некоторый интерфейс Fluent - еще одна вещь для изучения. Можно утверждать, что эта методология также «еще одна вещь для изучения».Ответы:
Пытается ли он написать фреймворк AOP "прямо в TDWTF"? Я серьезно до сих пор не понимаю, в чем его смысл. Как только вы говорите «Все методы должны принимать ровно один параметр», значит, вы потерпели неудачу, не так ли? На этом этапе вы говорите: «ОК», это накладывает некоторые серьезные искусственные ограничения на мою способность писать программы, давайте отбросим это сейчас, через три месяца, у нас будет полная ночная кошмарная кодовая база для работы.
И знаешь, что? С помощью Mono.Cecil вы можете легко написать простую инфраструктуру ведения журналов на основе атрибутов, основанную на IL . (тестирование это немного сложнее, но ...)
Да, и IMO, если вы не используете атрибуты, это не AOP. Весь смысл создания кода входа / выхода из метода на этапе постпроцессора заключается в том, чтобы он не мешал вашим файлам кода и не требовал думать об этом при рефакторинге кода; что является его мощность.
Все, что Грег продемонстрировал, - это глупая парадигма.
источник
let concat (x : string) y = x + y;; concat "Hello, " "World!";;
Похоже, что требуется два аргумента, что мне не хватает?concat "Hello, "
когда вы на самом деле создаете функцию, которая принимает простоy
и имеетx
предопределенную локальную привязку, которая будет «Hello». Если бы эту промежуточную функцию можно было увидеть, она бы выглядела примерно такlet concat_x y = "Hello, " + y
. И после этого вы звонитеconcat_x "World!"
. Синтаксис делает его менее очевидным, но это позволяет «запекать» новые функции - например,let printstrln = print "%s\n" ;; printstrln "woof"
. Кроме того, даже если вы делаете что-то подобноеlet f(x,y) = x + y
, на самом деле это всего лишь один аргумент кортежа .Боже мой, этот парень невыносимо абразивен. Я хотел бы просто прочитать код в вашем вопросе, а не смотреть этот разговор.
Я не думаю, что когда-либо использовал бы этот подход, если бы только ради использования AOP. Грег говорит, что это хорошо для простых ситуаций. Вот что я бы сделал в простой ситуации:
Да, я сделал это, я полностью избавился от АОП! Зачем? Потому что вам не нужен АОП в простых ситуациях .
С точки зрения функционального программирования, использование только одного параметра для каждой функции меня не пугает. Тем не менее, это действительно не тот дизайн, который хорошо работает с C # - и идти вразрез с языком вашего языка ничего не целует.
Я бы использовал этот подход только в том случае, если для начала нужно было создать модель команд, например, если мне нужен стек отмены или я работал с WPF Commands .
В противном случае я бы просто использовал рамки или некоторые отражения. PostSharp работает даже в Silverlight и Compact Framework - так , что он называет «волшебной» на самом деле не магическая вообще .
Я также не согласен с тем, чтобы избегать фреймворков ради возможности объяснить вещи юниорам. Это не приносит им никакой пользы. Если Грег относится к своим младшим так, как он предлагает, чтобы они относились к ним, как к тупым идиотам, то я подозреваю, что его старшие разработчики тоже не очень хороши, поскольку им, вероятно, не дали особой возможности чему-то научиться во время их младшие годы.
источник
Я сделал самостоятельное обучение в колледже на АОП. На самом деле я написал статью о подходе к модели AOP с помощью подключаемого модуля Eclipse. Это на самом деле несколько не имеет значения, я полагаю. Ключевые моменты: 1) я был молод и неопытен и 2) я работал с AspectJ. Я могу вам сказать, что «магия» большинства фреймворков AOP не так уж сложна. Я фактически работал над проектом примерно в то же время, когда пытался использовать подход с одним параметром, используя хеш-таблицу. ИМО, подход с одним параметром действительно является структурой, и это агрессивно. Даже в этом посте я потратил больше времени, пытаясь понять подход с одним параметром, чем анализируя декларативный подход. Я добавлю предостережение о том, что я не смотрел фильм, поэтому «магия» этого подхода может заключаться в использовании частичных приложений.
Я думаю, что Грег ответил на ваш вопрос. Вам следует переключиться на этот подход, когда вы думаете, что находитесь в ситуации, когда вы тратите слишком много времени на объяснение сред AOP для своих младших разработчиков. ИМО, если вы находитесь в этой лодке, вы, вероятно, нанимаете не тех младших разработчиков. Я не верю, что АОП требует декларативного подхода, но для меня это просто намного яснее и неинвазивен с точки зрения дизайна.
источник
IConsume<T>
пример слишком сложным для того, что делается.Если я не пропустил что-то, то код, который вы показали, является шаблоном проектирования «цепочки ответственности», который хорош, если вам нужно связать последовательность действий над объектом (например, команды, проходящие через серию обработчиков команд) в во время выполнения.
Использование AOP с помощью PostSharp хорошо, если во время компиляции вы знаете, какое поведение вы хотите добавить. Плетение кода в PostSharp в значительной степени означает отсутствие накладных расходов во время выполнения и делает код действительно чистым (особенно, когда вы начинаете использовать такие вещи, как многоадресные аспекты). Я не думаю, что базовое использование PostSharp особенно сложно объяснить. Недостатком PostSharp является то, что он значительно увеличивает время компиляции.
Я использую оба метода в производственном коде, и хотя есть некоторые совпадения в том, где они могут быть применены, я думаю, что по большей части они действительно нацелены на разные сценарии.
источник
Что касается его альтернативы - был там, сделал это. Ничто не сравнится с удобочитаемостью однострочного атрибута.
Прочитайте небольшую лекцию новым парням, объяснив им, как все работает в АОП.
источник
То, что описывает Грег, абсолютно разумно. И в этом тоже есть красота. Концепция применима в иной парадигме, чем чисто объектная ориентация. Это скорее процедурный подход или ориентированный на поток подход к проектированию. Поэтому, если вы работаете с унаследованным кодом, применить эту концепцию будет довольно сложно, поскольку может потребоваться много рефакторинга.
Я постараюсь привести еще один пример. Может быть, не идеально, но я надеюсь, что это проясняет ситуацию.
Таким образом, у нас есть служба продукта, которая использует репозиторий (в этом случае мы будем использовать заглушку). Сервис получит список товаров.
Конечно, вы также можете передать интерфейс для службы.
Далее мы хотим показать список продуктов в представлении. Поэтому нам нужен интерфейс
и команда, которая содержит список продуктов
и вид
Теперь нам нужен код, который выполняет все это. Это мы будем делать в классе под названием Application. Метод Run () - это интегрирующий метод, который не содержит или, по крайней мере, очень мало бизнес-логики. Зависимости вводятся в конструктор как методы.
Наконец, мы составляем приложение в основном методе.
Крутая вещь в том, что мы можем добавлять такие аспекты, как ведение журнала или обработка исключений, не затрагивая существующий код и не создавая структуру или аннотации. Например, для обработки исключений мы просто добавляем новый класс:
А затем мы подключаем его вместе во время композиции в точке входа приложения. нам даже не нужно трогать код в классе Application. Мы просто заменим одну строку:
Итак, возобновим: когда у нас есть ориентированный на поток дизайн, мы можем добавлять аспекты, добавляя функциональность в новый класс. Затем мы должны изменить одну строку в методе композиции и все.
Поэтому я думаю, что ответ на ваш вопрос заключается в том, что вы не можете легко переключиться с одного подхода на другой, но вам нужно решить, какой архитектурный подход вы выберете в своем проекте.
редактировать: На самом деле я только что понял, что частичный шаблон приложения, используемый со службой продукта, делает вещи немного сложнее. Нам нужно обернуть другой класс вокруг метода обслуживания продукта, чтобы иметь возможность добавлять аспекты и здесь. Это может быть что-то вроде этого:
Затем состав должен быть изменен следующим образом:
источник