По поводу возникшей в конференции ruFlash дискуссии насчет множественного наследования в компонентах v2 от Macromedia всплыл вопрос насчет так называемых mixins, которые присутствуют в аржитектуре этих компонент. Действительно, вопрос о mixins, насколько я знаю, в русскоязычных обзорах не поднимался и я попробую этот момент немного осветить. Для начала сам корень вопроса: Неоторые краем уха слышали, что в макромедийном фрэймворке, целиком написанном на ActionScript 2, проворачивается такая штука, как множественное наследование. А, как мы все знаем, ActionScript 2.0 - это язык программирования с полноценным объектно-ориентированным синтаксисом. Я не зря говорю про синтаксис, ибо только им дело и ограничевается. Тут даже не нужен никакой Нео чтобы открыть полог матрицы, не очень ловко прикрывающей торчащий из-под AS2 несвежо попахивающий AS1. Да, друзья мои, все мы хорошо знаем и скорбим, но AS2 компилируется в обычный AS1-байткод. А что есть такое AS1?
«ActionScript, как и его прообраз JavaScript, являются прототипированными языками. В прототипированных языках вы можете изменять определения класса на этапе исполнения и таким образом с легкостью добавлять функциональность. Вы добавляете методы другого класса в ваш класс путем достуупа к прототипу вашего класса.»
Понятное дело, что это я не сам такой умный, а привожу цитату из статьи, опубликованной на сайте Macromedia и посвященной mixins в Flex (считается, что Flex - это среда для серьезных разработчиков, ничего не знающих о тяжком прошлом Flash-разработчиков и потому для них специально объясняют всякие дикости; так или иначе, но все, что описывается в этой статье касается AS2 и Flex 1.x Components Framework, ноги которого растут напрямую из v2 components framework от Macromedia). Желающие могут сразу читать статью на английском, а для ленивых (шутка :) я продолжу тезисный обзор. «В ОО-языках mixins являются попыткой воплотить классы, отличающиеся от широкоиспользуемой практики пришедшей из Симулы (то, что используется в Smalltalk, C++, Java, C#). Впервые mixins использованы в Flavors (раннее объектно-ориентированное расширение Лиспа). Преимущество mixins в их способствовании повторному использованию кода и избегании широкоизвестных патологий, связанных с множественным наследованием, но между тем mixins имеют и собственный набор компромиссов. С mixins определение класса описывает только атрибуты и параметры, методы же определяются в других местах.»
Из этого Flavors (вкусы, привкусы, приправы) и родились mixins в программировании (как термин). А придуман он был так: в 1970-х годах в Массачусетском Технологическом Институте было популярное место встреч - Мороженое Стива (Steve's Ice Cream). Вы могли сделать собственное мороженое просто выбрав основу и различные добавки, которые назывались mixins.
Понятно, что в этих вот широкоиспользуемых ОО-языках типа Java mixins представляют тот "душок" (code that smells), который устраняется путем рефакторинга и более продуманной и изящной архитектуры с более понятным и читаемым кодом. И, стремясь к лучшим образцам (об этом в коце статьи), мы (вернее Macromedia) и с помощью AS2 вполне можем избежать этих mixins, о которых так долго уже говорим, но вы, думаю, так еще и не поняли, о чем я конкретно толкую. Хорошо, перейдем к примеру.
Наиболее употребимый пример mixins - это использование событийной модели и класса mx.events.EventDispatcher. Вы создаете собственный класс и желаете иметь в нем ту же событийную модель, что и в остальных классах от Macromedia (в рамках пакета mx). А также вы хотите чтобы ваш класс был отнаследован от класса, такой модели не имеющего. Что вы делаете? Вы пишете:
Created with Colorer-take5 Library. Type 'actionscript'
0: import mx.events.EventDispatcher;
1: 
2: class Client extends Date
3: {
4:  public function Client ()
5:  {
6:   EventDispatcher.initialize (this);
7:  }
8: }
И все. А дальше в дело вступают эти самые mixins. В классе mx.events.EventDispatcher мы видим:
 13: class mx.events.EventDispatcher
 14: {
     .............
 43:  static function initialize(object:Object):Void
 44:  {
 45:   if (_fEventDispatcher == undefined)
 46:   {
 47:    _fEventDispatcher = new EventDispatcher;
 48:   }
 49:   object.addEventListener = _fEventDispatcher.addEventListener;
 50:   object.removeEventListener = _fEventDispatcher.removeEventListener;
 51:   object.dispatchEvent = _fEventDispatcher.dispatchEvent;
 52:   object.dispatchQueue = _fEventDispatcher.dispatchQueue;
 53:  }
      ..............................
 143: }
144: 
Именно здесь и совершается таинство mixins. Понятно, что для того чтобы методы addEventListener и removeEventListener нормально обрабатывались нашей IDE и компилятором, необходимо в классе Client присутствовали заглушки этих методов: просто для синтаксических нужд, не более. Есть два основных способа: написать их как свойства класса типа Function (тогда не будут проверяться компилятором типы параметров) и в виде метода с реальной сигнатурой, но без всякой имплементации (наподобии Template Method, но все-таки не он). Я рассматриваю два вида техники mixins, которые существуют в AS2: добавление методов в класс (через ключевое слово prototype) и добавление методов в экземпляр (как в рассмотренном выше примере). Оба эти способа широко используются в макромедийных классах.
Недостатки такого способа очевидны: мы теряем контроль над кодом. Здесь есть два уровня этого недостатка: концептуальный и уровень конкретной реализации. На концептуальном уровне беспокоит возможность такого поведения языка программирования в принципе. Я не могу доверять стороннему коду пока досконально его не изучу: в таком подходе структура кода на уровне сигнатур методов и определения класса (то есть, скажем, изучение intrinsic-определения класса если он поставляется без исходного кода) я не могу быть твердо уверенным, что этот код не содержит чего-то такого, что меняет поведение и моего кода! Я могу делать любые предположения при отладке, но действительность может сыграть со мной гораздо более злую шутку: для переопределения через прототипы нет модификаторов public/private (как нет их в AS1)!
Уровень же конкретной реализации как минимум может предоставить мне трудноразгадываемую головоломку при разборе кода. И как максимум (в качестве следствия) - неуправляемую сложность кода, с трудом поддающегося отладке (не поможет ни синтаксический анализатор, ни компилятор).
А плюс только один - легкий путь избавления от дублирования кода. Как будто нет наработанной базы приемов рефакторинга, паттернов проектирования (они все ведут к той же цели!).
Но есть еще более существенный довод в пользу того чтобы понимать компромиссную природу mixins и знать, что заставляет их нас использовать сейчас, но не полагаться на них при других условиях: мы имеем уникальную возможность заглянуть в будущее. В ActionScript 3 у нас не будет ни прототипирования, ни возможности переопределять методы экземпляров. Не верите? Что же, запустите нижеприведенный код в Flex 2 Alpha и убедитесь сами: 
 0: package cats.mixins {
 1:  import flash.util.trace;
 2:  
 3:  public class Client 
 4:  {
 5:   public function Client ()
 6:   {
 7:    EventDispatcher.initialize (this);
 8:   }
 9:   
10:   public function addEventListener(event:String, handler:Function):Void
11:   {
12:    trace ("own addEventListener");
13:   }
14:  }
15:  
16:  private class EventDispatcher
17:  {
18:   private static var _fEventDispatcher:EventDispatcher;
19:   
20:   internal static function initialize (object:Object):Void
21:   {
22:    if (EventDispatcher._fEventDispatcher == null)
23:    {
24:     EventDispatcher._fEventDispatcher = new EventDispatcher ();
25:    }
26:    object.addEventListener = _fEventDispatcher.addEventListener;
27:   }
28:   
29:   private function addEventListener(event:String, handler:Function):Void
30:   {
31:    trace ("mixing addEventListener success!");
32:   }
33:  }
34: }
  
  
 0: package 
 1: {
 2:  import flash.display.MovieClip;
 3:  import cats.mixins.Client;
 4:  
 5:  public class Cats extends MovieClip 
 6:  {
 7:   public function Cats() 
 8:   {
 9:    var aClient:Client = new Client ();
10:    aClient.addEventListener ("someEvent", handler);
11:   }
12:   
13:   private function handler ():Void
14:   {
15:    
16:   }
17:  }
18: }
Я просто имитировал ситуацию с mx.events.EventDispatcher, средствами AS3. И получил логичный runtime error:
ReferenceError: Error #1037: Cannot assign to a method addEventListener on cats.mixins.Client
 at cats.mixins$6$private::EventDispatcher$/cats.mixins$internal::initialize()
 at cats.mixins::Client$iinit()
 at Cats$iinit()
И вот уже в AS3 проблема с механизмом обработки событий решена гораздо изящнее: класс flash.events.EventDispatcher является суперклассом ряда классов, которые в нем нуждаются. А если не является - можно включить его в качестве композита. Думаю, что на этом вполне можно закончить. Если вам понравился данный материал, то просьба выражать благодарности его инициатору Евгению Н. Спасибо.