В чем разница между Decorator, Attribute, Aspect и Trait?

С точки зрения чистой информатики (или, возможно, вычислительной лингвистики), я хотел бы знать разницу между словами:

  • декоратор
  • Атрибут
  • Aspect
  • Тре

Различные языки используют эти слова и функциональные возможности разным образом. В Python, например, Decorators [в соответствии с Python Wiki] (выделено мной):

Декораторы динамически изменяют функциональность функции, метода или класса без прямого использования подклассов или изменения исходного кода выполняемой функции.

Это поражает меня как удивительно похожего на инструмент с ориентированным ориентиром, например PostSharp или DynamicProxy. то есть:.

   [Profile]
   private static void SleepSync()
   {
       Thread.Sleep(200);
   }

Источник: Примеры PostSharp

В С# и Java (а также множество других языков) атрибуты могут означать либо декоратор-иш-шаблон (С#), либо поле (Java).

И в С++ с помощью boost или PhP с помощью встроенного слова , мы можем использовать черты для расширения классов, как показано здесь: https://en.wikipedia.org/wiki/Trait_(computer_programming)

Итак, с "чистой" точки зрения, каковы канонические определения того, что все это на самом деле? Есть ли лучший способ определить их?

Ответ 1

декоратор

Я думаю о Decorator с точки зрения дизайна. Шаблоны проектирования распознаются на многих языках, особенно объектно-ориентированных. Затем декоратор как шаблон является оберткой, которая добавляет функциональность, не присутствующую в функции или классе, украшенном.

Самый простой пример, о котором я могу думать, - это функция декоратора. Функция

int foo(int x)

может быть украшена другой функцией, которая принимает второй параметр, делает с ней что-то еще, а затем в свою очередь вызывает foo(), передавая исходный параметр x.

int bar(int x, int y) {
    return y*y + foo(x);
}

Хотя шаблоны проектирования обычно применяются на уровне класса, принцип здесь один и тот же, и я думаю, что он хорошо иллюстрирует то, что понимается декоратором. Соответствует ли каждый конкретный язык этому вопросу. На одном языке может быть что-то еще, что он называет "декоратором", но для меня эта концепция лучше всего соответствует идее декорирования чего-то простого с дополнительной функциональностью без изменения исходного кода или даже использования наследования.

Другим распространенным примером являются классы ввода-вывода в Java. Существует базовый

OutputStream s

а затем вы можете украсить это, используя более специализированные классы в зависимости от типа обрабатываемых данных, или формат, который вы хотите прочитать в:

OutputStream s1 = new FileOutputStream("somefile.txt");

или

OutputStream s2 = new ByteOutputStream("rawdata.hex");

Атрибут

Я бы склонялся к идее С# атрибута, являющегося правильным пониманием, потому что он отличается от декоратора. Атрибут присваивает семантическое значение, которое может варьироваться от объекта к объекту, и даже между API, которые используют один и тот же атрибут. Например, у меня могут быть два объекта:

[Logging] Object a;
[Security] Object b;

Я могу назначить один атрибут ведения журнала и один атрибут безопасности, и что означают эти атрибуты, может отличаться от клиентского API, который проверяет эти атрибуты. Можно использовать log4j для реализации журнала, и можно использовать другой API. Определение здесь намного более актуально и доступно для интерпретации различными сторонами или пользователями моего кода. Конечно, можно использовать атрибут для работы в качестве декоратора, но атрибуты могут использоваться гораздо больше.

Как раз для значения, атрибут слова также используется для обозначения переменных-членов класса. Здесь мы говорим о более широкой, более абстрактной концепции назначения предопределенного семантического значения существующему объекту или классу. Java вызывает эти аннотации.

Один из моих определителей, поскольку это атрибут, в том смысле, о котором мы говорим, состоит в том, что он не влияет непосредственно на поведение, только косвенно. Например, присвоение атрибуту [Logging] к чему-то не меняет его код. Это похоже на прикрепление тега имени, который другие ищут. Когда другая программа или приложение видит тег имени, он обнаруживает определенные вещи и может соответствующим образом изменять свое поведение. Но (по крайней мере, на Java) аннотации или атрибуты напрямую не изменяют ничего - опять же, просто тег имени. Это может немного отличаться на С# или других языках, поддерживающих атрибуты, и в этом случае я считаю их более продвинутым атрибутом или чем-то еще полностью.

Aspect

Аспект в аспекте аспектно-ориентированного программирования (AOP) - это своего рода самомодифицирующаяся или самообновляющаяся конструкция кода. Он определяет секцию кода как более податливую (точечный срез) и позволяет обменивать конкретный раздел между одним или несколькими возможными обновлениями, исправлениями или разными версиями одного и того же раздела кода.

Не могли бы вы сделать некоторые из тех же вещей, что и декораторы и атрибуты, используя аспекты? Конечно. Но почему бы вам дать эту головную боль? АОП походит на следующий шаг вверх от ООП, только он должен использоваться, когда это необходимо. Когда это необходимо? Когда конкретное приложение имеет множество "сквозных проблем", таких как безопасность или ведение журнала, например, банковское приложение. Это касается перекрестного разреза; они выходят за рамки традиционных границ, которые делают хорошие определенные классы и пакеты. Когда вы регистрируетесь, это не очень полезно, если вы не регистрируете все; следовательно, эта проблема является сквозной. Поэтому, когда вы переходите к обновлению механизма журналирования одного класса, было бы сложно одновременно изменить все другие классы и API, но это также было бы необходимо. В противном случае ваше ведение журнала теперь является непоследовательным и запутанным, а более сложным для устранения неполадок или мониторинга.

Чтобы сделать эти виды обновлений меньше головной боли, были представлены аспектно-ориентированные языки, такие как AspectJ. Я не сталкивался с "аспектом", который означал что-то другое, кроме этого, но могут быть некоторые, как было сказано ранее, о декораторах. Определенный язык может назвать какой-то аспект, но он может больше походить на одну из других вещей, которые мы уже обсуждали.

Тре

Тит является синонимом интерфейса или, по крайней мере, тем, как он выглядит на языках, которые я изучал.

Интерфейс представляет собой концепцию ООП, которая объявляет поведение без их реализации. Создание этих ожидаемых действий позволяет этим поведениям стать универсальными и вызываться в целом, не заботясь о специфике. Он оставил подклассы для их реализации.

Классическим примером ООП является Animal, с двумя подклассами Cat и Dog.

public interface/trait Animal {
    public void speak();
}
public class Cat implements Animal {
    public void speak() {
        output("Meow.");
    }
}
public class Dog implements Animal {
    public void speak() {
         output("Bark!");
    }
}

Это также отличный пример полиморфизма - одно из тех слов, которые, как правило, заставляют некрупных людей съеживаться. Это просто означает, что у кошки и собаки есть индивидуальное поведение, и если я объявляю объект Animal, мне все равно, что бы вы мне дали. Вы можете дать мне кошку или собаку. Поскольку оба являются животными, в любом случае все, что мне нужно сделать, это вызвать функцию speak() моего объекта Animal, и я могу быть уверен, что правильный результат будет иметь место в любом случае. Каждый отдельный подкласс знает, что ему нужно делать. В С++ воды здесь немного более грязные, но общее понятие одно и то же (читайте в ключевое слово "virtual", если вы хотите начать эту кроличью нору).

Wrap-Up

Я надеюсь, что это устранит некоторую путаницу. Кажется, что, как вы сказали, многие разные языки имеют много разных значений для каждого из них, без сомнения, способствуют путанице. Я считаю, что если вы посмотрите дальше, вы обнаружите, что в целом это стандартные значения. Я программировал на многих языках (VB, С++, С#, Java, Paschal, PHP, Perl) в течение 18 лет, и это те определения, которые мне больше всего нравятся, полагая, что это своего рода стандарт.

Я, конечно, приветствую дальнейшее обсуждение того, что я сказал.