stringtranslate.com

Метакласс

В объектно-ориентированном программировании метакласс — это класс , экземпляры которого также являются классами. Подобно тому, как обычный класс определяет поведение определенных объектов, метакласс определяет поведение определенных классов и их экземпляров. Не все объектно-ориентированные языки программирования поддерживают метаклассы. Среди тех, кто это делает, степень, в которой метаклассы могут переопределять любой аспект поведения класса, варьируется. Метаклассы могут быть реализованы, если классы являются первоклассными гражданами , и в этом случае метакласс — это просто объект, который создает классы. Каждый язык имеет свой собственный метаобъектный протокол — набор правил, которые управляют взаимодействием объектов, классов и метаклассов. [1]

Пример Python

В Python встроенный класс typeявляется метаклассом. [2] [3] [4] Рассмотрим этот простой класс Python:

class  Car :  def  __init__ ( self ,  марка :  str ,  модель :  str ,  год :  int ,  цвет :  str ):  self . сделать  =  сделать  себя . модель  =  модель  себя . год  =  год  себя . цвет  =  цвет @property  def  описание ( self )  ->  str : " " " Вернуть описание этой машины.""" return f " { self.color } { self . make } { self . model } "     

Во время выполнения Carон сам является экземпляром type. Исходный код класса Car, показанного выше, не включает в себя такие детали, как размер Carобъектов в байтах, их двоичное расположение в памяти, способ их распределения, __init__автоматический вызов метода при каждом Carсоздании и так далее. Эти детали вступают в игру не только при Carсоздании нового объекта, но и каждый раз, когда Carосуществляется доступ к любому атрибуту объекта. В языках без метаклассов эти детали определяются спецификацией языка и не могут быть переопределены. В Python метакласс - type- управляет этими деталями Carповедения. Их можно переопределить, используя другой метакласс вместо type.

Приведенный выше пример содержит некоторый избыточный код для четырех атрибутов make, model, yearи color. Эту избыточность можно устранить с помощью специального метакласса. В Python метакласс проще всего определить как подкласс type.

class  AttributeInitType ( type ):  def  __call__ ( self ,  * args ,  ** kwargs ): """Создать новый экземпляр."""  # Сначала создайте объект обычным способом по умолчанию.  объект  =  тип . __call__ ( я ,  * аргументы ) # Кроме того, установите атрибуты нового объекта.  для  имени значение в кваргах  . _ элементы (): setattr ( объект , имя , значение )      # Возвращаем новый объект.  вернуть  объект

Этот метакласс переопределяет только создание объекта. Все остальные аспекты поведения классов и объектов по-прежнему обрабатываются type.

Теперь класс Carможно переписать для использования этого метакласса. В Python 3 это делается путем предоставления «аргумента ключевого слова» metaclassв определении класса:

class  Car ( объект ,  метакласс = AttributeInitType ):  @property  def  описание ( self )  ->  str : """Вернуть описание этого автомобиля.""" return " " . join ( str ( value ) for value in self . __dict__ . values ())       

Результирующий объект Carможет быть создан как обычно, но может содержать любое количество аргументов-ключевых слов:

new_car  =  Автомобиль ( марка = «Toyota» ,  модель = «Приус» ,  год = 2005 ,  цвет = «Зеленый» ,  двигатель = «Гибрид» )

В Смолталке-80

Иерархия метаклассов Smalltalk-80 как диаграмма UML
Диаграмма отношений наследования и экземпляров между классами и метаклассами в Smalltalk

В Smalltalk все является объектом . Кроме того, Smalltalk — это система , основанная на классах , что означает, что у каждого объекта есть класс, который определяет структуру этого объекта (т. е. переменные экземпляра, которые имеет объект) и сообщения, которые объект понимает. В совокупности это означает, что класс в Smalltalk является объектом и, следовательно, класс должен быть экземпляром класса (называемого метаклассом).

Например, объект автомобиля cявляется экземпляром класса Car. В свою очередь, класс Carснова является объектом и, как таковой, экземпляром метакласса Carвызываемого Car class. Обратите внимание на пробел в названии метакласса. Имя метакласса — это выражение Smalltalk, при вычислении которого создается объект метакласса. Таким образом, оценка Car classрезультатов в объекте метакласса, Carимя которого Car class(это можно подтвердить, вычислив Car class name, который возвращает имя метакласса Car.)

Методы класса фактически принадлежат метаклассу, так же как методы экземпляра фактически принадлежат классу. Когда объекту отправляется сообщение 2, начинается поиск метода в Integer. Если он не найден, он переходит вверх по цепочке суперклассов, останавливаясь на объекте, независимо от того, найден он или нет.

Когда сообщение отправляется на Integerпоиск метода, начинается Integer classи продолжается вверх по цепочке суперклассов до Object class. Обратите внимание, что до сих пор цепочка наследования метаклассов точно соответствует цепочке наследования классов. Но цепочка метаклассов простирается дальше, поскольку Object classявляется подклассом Class. Все метаклассы являются подклассами класса Class.

В ранних версиях Smalltalks был только один метакласс под названием Class. Это подразумевало, что методы всех классов были одинаковыми, в частности метод создания новых объектов, newт.е. Чтобы позволить классам иметь свои собственные методы и свои собственные переменные экземпляра (называемые переменными экземпляра класса, и их не следует путать с переменными класса ), Smalltalk-80 ввел для каждого класса Cсвой собственный метакласс C class. Это означает, что каждый метакласс фактически является одноэлементным классом.

Поскольку не требуется, чтобы метаклассы вели себя иначе, все метаклассы являются экземплярами только одного класса, называемого Metaclass. MetaclassВызывается метакласс Metaclass class, который снова является экземпляром класса Metaclass.

В Smalltalk-80 каждый класс (кроме Object) имеет суперкласс . Абстрактным суперклассом всех метаклассов является Class, который описывает общую природу классов.

Иерархия суперклассов для метаклассов аналогична иерархии классов, за исключением class Object. ВСЕ метаклассы являются подклассами Class, поэтому:

Подобно сиамским близнецам , классы и метаклассы рождаются вместе. Metaclassимеет переменную экземпляра thisClass, которая указывает на связанный с ним класс. Обратите внимание, что обычный браузер классов Smalltalk не отображает метаклассы как отдельные классы. Вместо этого браузер классов позволяет одновременно редактировать класс вместе с его метаклассом.

Имена классов в иерархии метаклассов легко спутать с одноименными понятиями. Например:

Четыре класса предоставляют возможности для описания новых классов. Их иерархия наследования (от Object) и основные возможности, которые они предоставляют:

Объект — поведение по умолчанию, общее для всех объектов, например доступ к классу.
Поведение — минимальное состояние для компиляции методов и создания/запуска объектов.
ClassDescription ( абстрактный класс ) — имя класса/переменной, комментарии.
Класс - аналогичные, более полные возможности суперклассов.
Метакласс — инициализация переменных класса, сообщения о создании экземпляра

В Рубине

Ruby очищает концепцию метаклассов Smalltalk-80, вводя собственные классы, удаляя Metaclassкласс и (не)переопределяя карту класса. Это изменение можно схематически представить следующим образом: [5]

Обратите особое внимание на соответствие между неявными метаклассами Smalltalk и собственными классами классов Ruby. Модель собственных классов Ruby делает концепцию неявных метаклассов полностью единообразной: каждый объект x имеет свой собственный мета-объект, называемый собственным классом x , который на один метауровень выше, чем x . Собственные классы «высшего порядка» обычно существуют чисто концептуально — они не содержат никаких методов и не хранят никаких (других) данных в большинстве программ Ruby. [6]

На следующих диаграммах показан пример базовой структуры Smalltalk-80 и Ruby в сравнении. [7] В обоих языках структура состоит из встроенной части, которая содержит циклические объекты (т.е. объекты, которые появляются в цикле, образованном комбинацией синих или зеленых ссылок), и пользовательскую часть, которая имеет четыре явных объекта: классы Aи Bтерминальные объекты uи v. Зеленые ссылки показывают отношение наследования дочерний → родительский (с неявным направлением вверх), синие ссылки показывают дополнительное отношение член → контейнер создания экземпляра (синяя ссылка от x указывает на наименее реальный контейнер x , который является начальной точкой для поиск метода при вызове метода для x ). Серые узлы отображают собственные классы (соответственно неявные метаклассы в случае Smalltalk-80).

Диаграмма справа также дает представление о ленивом вычислении собственных классов в Ruby. Собственный класс объекта vможет быть оценен (выделен) в результате добавления одноэлементных методов в v.

Согласно методу интроспекции Ruby class, класс каждого класса (и каждого собственного класса) всегда является Classклассом (обозначенным cна диаграмме). Classи Structявляются единственными классами, экземплярами которых являются классы. [8] [ оспаривается ] Создание подклассов Classзапрещено. Следуя стандартному определению метаклассов, мы можем заключить, что Classи Structявляются единственными метаклассами в Ruby. Кажется, это противоречит соответствию между Ruby и Smalltalk, поскольку в Smalltalk-80 каждый класс имеет свой собственный метакласс. Несоответствие основано на разногласиях между classметодом интроспекции в Ruby и Smalltalk. Хотя карта x ↦ x.class на терминальных объектах совпадает, отличается ограничением на классы. Как уже упоминалось выше, для класса xвыражение Ruby x.classпостоянно оценивается как Class. В Smalltalk-80, если xэто класс, то выражение x classсоответствует Ruby x.singleton_class, что соответствует собственному классу x.

В Objective-C

Диаграмма отношений наследования и экземпляров между классами и метаклассами в Objective-C. Обратите внимание, что Objective-C имеет несколько корневых классов; каждый корневой класс будет иметь отдельную иерархию. На этой диаграмме показана иерархия только для примера корневого класса NSObject. Каждый другой корневой класс будет иметь аналогичную иерархию.

Метаклассы в Objective-C почти такие же, как в Smalltalk-80, что неудивительно, поскольку Objective-C многое заимствует у Smalltalk. Как и в Smalltalk, в Objective-C переменные и методы экземпляра определяются классом объекта. Класс — это объект, следовательно, он является экземпляром метакласса.

Как и в Smalltalk, в Objective-C методы класса — это просто методы, вызываемые для объекта класса, поэтому методы класса класса должны быть определены как методы экземпляра в его метаклассе. Поскольку разные классы могут иметь разные наборы методов класса, каждый класс должен иметь свой отдельный метакласс. Классы и метаклассы всегда создаются парами: среда выполнения имеет функции objc_allocateClassPair()для objc_registerClassPair()создания и регистрации пар класс-метакласс соответственно.

Для метаклассов нет названий; однако на указатель на любой объект класса можно ссылаться с помощью универсального типа Class(аналогично типу, idиспользуемому для указателя на любой объект).

Поскольку методы класса наследуются посредством наследования, как в Smalltalk, метаклассы должны следовать схеме наследования, параллельной схеме наследования классов (например, если родительским классом класса A является класс B, то родительским классом метакласса A является метакласс B), за исключением корневого класса.

В отличие от Smalltalk, метакласс корневого класса наследуется от самого корневого класса (обычно NSObjectс использованием инфраструктуры Cocoa ). Это гарантирует, что все объекты класса в конечном итоге являются экземплярами корневого класса, так что вы можете использовать методы экземпляра корневого класса (обычно полезные служебные методы для объектов) на самих объектах класса.

Поскольку объекты метакласса не ведут себя по-разному (вы не можете добавлять методы класса для метакласса, поэтому все объекты метакласса имеют одинаковые методы), все они являются экземплярами одного и того же класса — метакласса корневого класса (в отличие от Smalltalk). Таким образом, метакласс корневого класса является экземпляром самого себя. Причина этого в том, что все метаклассы наследуются от корневого класса; следовательно, они должны наследовать методы корневого класса. [9]

Поддержка языков и инструментов

Ниже приведены некоторые из наиболее известных языков программирования , поддерживающих метаклассы.

Некоторые менее распространенные языки, поддерживающие метаклассы, включают OpenJava , OpenC++, OpenAda, CorbaScript , ObjVLisp, Object-Z , MODEL-K , XOTcl и MELDC. Некоторые из этих языков датируются началом 1990-х годов и представляют академический интерес. [11]

Logtalk , объектно-ориентированное расширение Пролога , также поддерживает метаклассы.

Структура описания ресурсов (RDF) и унифицированный язык моделирования (UML) поддерживают метаклассы.

Смотрите также

Рекомендации

  1. ^ Ира Р. Форман и Скотт Дэнфорт (1999). Использование метаклассов в работе . ISBN 0-201-43305-2.
  2. ^ Программирование IBM Metaclass на Python, части 1. Архивировано 3 сентября 2008 г. на Wayback Machine , 2 и 3.
  3. ^ Форум Artima: Метаклассы в Python 3.0 (часть 1 из 2) (часть 2 из 2)
  4. ^ Дэвид Мерц. «Букварь по программированию метаклассов Python». ONLamp . Архивировано из оригинала 30 апреля 2003 года . Проверено 28 июня 2006 г.
  5. ^ «Объектная модель Ruby: сравнение со Smalltalk-80».
  6. ^ Паоло Перротта (2010). Метапрограммирование Ruby. Прагматичная книжная полка. ISBN 978-1-934356-47-0.
  7. ^ «Членство объекта: основная структура объектной технологии».
  8. ^ "Структура". Руби Док . Проверено 1 мая 2015 г.
  9. ^ Какао с любовью: Что такое метакласс в Objective-C?
  10. ^ Херб Саттер . «Метаклассы» (PDF) .
  11. ^ «Реализация примесей в Java с использованием метаклассов» (PDF) . Архивировано из оригинала (PDF) 16 октября 2007 г. Проверено 27 ноября 2007 г.