В чем разница между декоратором, атрибутом, аспектом и чертой?

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

  • оформителя
  • атрибут
  • аспект
  • черта

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

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

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

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

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

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

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

1 ответов


оформителя

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

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

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");

атрибут

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

[Logging] private void a() { ... }
[Security] private void b() { ... }

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

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

аспект

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

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

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

признак

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

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

классический ООП пример-животное, с двумя подклассами, кошка и собака.

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!");
    }
}

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

Подведение Итогов

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

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