Декоратор
Я думаю о 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");
or
OutputStream s2 = new ByteOutputStream("rawdata.hex");
Атрибут
Я бы склонялся к идее С# о том, что атрибут является правильным пониманием, потому что он отличается от декоратора. Атрибуту присваивается семантическое значение, которое может варьироваться от одного использования к другому и даже между API, использующими один и тот же атрибут. Например, у меня может быть две функции:
[Logging] private void a() { ... }
[Security] private void b() { ... }
Я могу назначить один атрибут регистрации и один атрибут безопасности, и то, что означают эти атрибуты, может отличаться от клиентских API, которые проверяют эти атрибуты. Можно использовать log4j для реализации ведения журнала, а можно использовать другой API. Определение здесь гораздо более гибкое и открытое для интерпретации разными сторонами или пользователями моего кода. Конечно, можно использовать атрибут в качестве декоратора, но атрибуты можно использовать и для гораздо большего.
Просто для устранения неоднозначности слово атрибут также используется для обозначения переменных-членов класса. Здесь мы говорим о более широкой и абстрактной концепции присвоения предопределенного семантического значения существующему объекту или классу. Java называет эти аннотации.
Я считаю, что одним из определяющих факторов, определяющих, что это Атрибут, в том смысле, о котором мы говорим, является то, что он не изменяет поведение напрямую, а только косвенно. Например, присвоение чему-либо атрибута [Ведение журнала] никак не меняет его код. Это как прикрепить бирку с именем, которую ищут другие. Когда другая программа или приложение видит тег имени, она делает определенные выводы и может соответствующим образом изменить свое поведение. Но (по крайней мере, в Java) аннотации или атрибуты напрямую ничего не изменяют — опять же, только тег имени. Это может немного отличаться в C# или других языках, поддерживающих атрибуты, и в этом случае я бы считал их более продвинутым атрибутом или чем-то совершенно другим.
Аспект
Аспект в смысле аспектно-ориентированного программирования (АОП) — это своего рода самомодифицирующаяся или самообновляющаяся конструкция кода. Он определяет участок кода как более гибкий (точечный разрез) и позволяет переключать этот конкретный участок между одним или несколькими возможными обновлениями, исправлениями или разными версиями одного и того же участка кода.
Не могли бы вы сделать некоторые из тех же вещей, что и декораторы и атрибуты, используя аспекты? Конечно. Но зачем вы себе эту головную боль? АОП — это следующий шаг по сравнению с ООП, только его следует использовать при необходимости. Когда это необходимо? Когда конкретное приложение имеет много «сквозных проблем», таких как безопасность или ведение журнала, например, банковское приложение. Эти проблемы пересекаются; они выходят за традиционные границы, которые создают хорошо определенные классы и пакеты. Когда вы ведете журнал, это не приносит большой пользы, если вы не регистрируете все; следовательно, эта озабоченность носит сквозной характер. Поэтому, когда вы собираетесь обновить механизм ведения журнала одного класса, будет сложно одновременно изменить все остальные классы и 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, и я могу быть уверен, что в любом случае будет получен правильный результат. Каждый отдельный подкласс знает, что ему нужно делать. В C++ вода здесь немного более мутная, но общая концепция такая же (прочитайте ключевое слово «виртуальный», если вы хотите начать спускаться по этой кроличьей норе).
Подведение итогов
Я надеюсь, что это проясняет некоторую путаницу. Кажется, что, как вы сказали, многие разные языки имеют много разных значений для каждого из них, что, несомненно, способствует путанице. Я полагаю, что если вы вникнете в это глубже, то обнаружите, что по большому счету это стандартные значения. Я программировал на многих языках (VB, C++, C#, Java, Paschal, PHP, Perl) более 18 лет, и мне удобнее всего считать эти определения своего рода стандартами.
Я, безусловно, приветствую дальнейшее обсуждение того, что я сказал.
person
Tim
schedule
02.11.2016