Изменить: изменения добавлены, потому что некоторые люди считают, что я несу ответственность за ограничения Objective-C.
Короткий ответ: нельзя. В Objective-C нет эквивалента примесей Ruby.
Чуть менее короткий ответ: в Objective-C есть что-то похожее: протоколы. Протоколы (интерфейсы на некоторых других языках) — это способ определить набор методов, которые класс, принимающий эти протоколы, обязуется реализовать. Однако протокол не обеспечивает реализацию. Это ограничение не позволяет использовать протоколы как точные эквиваленты примесей Ruby.
Еще менее краткий ответ: Однако среда выполнения Objective-C имеет открытый API, который позволяет вам экспериментировать с динамическими функциями языка. Затем вы выходите за пределы языка, но можете иметь протоколы с реализациями по умолчанию (также называемые конкретными протоколами). Ответ Владимира показывает один из способов сделать это. В этот момент мне кажется, что вы хорошо понимаете миксины Ruby.
Однако я не уверен, что рекомендовал бы это делать. В большинстве случаев другие шаблоны удовлетворяют всем требованиям, не играя в игры со средой выполнения. Например, у вас может быть подобъект, реализующий смешанный метод (имеет-а вместо является-а). Играть со средой выполнения можно, но есть 2 недостатка:
Вы делаете свой код менее читаемым, так как он требует от читателей знания гораздо большего, чем язык. Конечно, вы можете (и должны) прокомментировать его, но помните, что любой необходимый комментарий может рассматриваться как дефект реализации.
Вы зависите от этой реализации языка. Конечно, платформы Apple являются наиболее распространенными для Objective-C, но не забывайте Cocotron или GnuStep (или Etoilé), которые имеют разные среды выполнения, которые могут быть или не быть совместимыми с Apple в этом отношении.
В качестве примечания ниже я заявляю, что категории не могут добавлять состояние (переменные экземпляра) к классу. Используя API среды выполнения, вы также можете снять это ограничение. Однако это выходит за рамки этого ответа.
Длинный ответ:
Две функции Objective-C выглядят как возможные кандидаты: категории и протоколы. Категории здесь не совсем правильный выбор, если я правильно понимаю вопрос. Правильная функция — это протокол.
Позвольте мне привести пример. Предположим, вы хотите, чтобы у группы ваших классов была особая способность под названием «петь». Затем вы определяете протокол:
@protocol Singer
- (void) sing;
@end
Теперь вы можете объявить, что любой из ваших собственных классов принимает протокол следующим образом:
@interface Rectangle : Shape <Singer> {
<snip>
@end
@interface Car : Vehicle <Singer> {
<snip>
@end
Заявляя, что они принимают протокол, они обязуются реализовать метод sing
. Например:
@implementation Rectangle
- (void) sing {
[self flashInBrightColors];
}
@end
@implementation Car
- (void) sing {
[self honk];
}
@end
Затем вы используете эти классы, например, так:
void choral(NSArray *choir) // the choir holds any kind of singer
{
id<Singer> aSinger;
for (aSinger in choir) {
[aSinger sing];
}
}
Обратите внимание, что певцы в массиве не обязательно должны иметь общий суперкласс. Заметьте также, что у класса может быть только один суперкласс, но много принятых протоколов. Наконец, обратите внимание, что проверка типов выполняется компилятором.
По сути, механизм протокола представляет собой множественное наследование, используемое для шаблона миксина. Это множественное наследование сильно ограничено, поскольку протокол не может добавлять в класс новые переменные экземпляра. Протокол описывает только общедоступный интерфейс, который должны реализовать пользователи. В отличие от модулей Ruby, он не содержит реализации.
Это самое главное. Однако давайте упомянем категории.
Категория объявляется не в угловых скобках, а между скобками. Разница в том, что для существующего класса можно определить категорию, чтобы расширить его, не создавая подклассов. Вы даже можете сделать это для системного класса. Как вы понимаете, можно использовать категории для реализации чего-то похожего на миксин. И так они долгое время использовались обычно как категория к NSObject
(типичный корень иерархии наследования), до такой степени, что их называли "неформальными" протоколами.
Это неформально, потому что 1- компилятор не выполняет проверку типов и 2- реализация методов протокола не является обязательной.
Сегодня нет необходимости использовать категории в качестве протоколов, особенно потому, что формальные протоколы теперь могут объявлять некоторые из своих методов необязательными с ключевым словом @optional
или обязательными (по умолчанию) с @required
.
Категории по-прежнему полезны для добавления определенного поведения в существующий класс. NSString
является общей целью для этого.
Также интересно отметить, что большинство (если не все) NSObject
средств на самом деле объявлены в NSObject
протоколе. Это означает, что на самом деле не обязательно использовать NSObject
в качестве общего суперкласса для всех классов, хотя это все еще обычно делается по историческим причинам, и... потому что в этом нет никаких недостатков. Но некоторые системные классы, такие как NSProxy
, не NSObject
.
person
Jean-Denis Muys
schedule
21.03.2010