Подтвердить что ты не робот

Поддерживает ли Objective-C Mixin как Ruby?

В Ruby есть модули, и вы можете расширить класс путем "смешивания" модуля.

module MyModule
  def printone
    print "one" 
  end
end

class MyClass
  include MyModule
end

theOne = MyClass.new
theOne.printone 
>> one

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

4b9b3361

Ответ 1

Изменить: добавлены изменения, потому что некоторые люди считают, что я несу ответственность за ограничения Objective-C.

Короткий ответ: вы не можете. Objective-C не имеет эквивалента Ruby mixins.

Слегка менее короткий ответ: Objective-C имеет что-то, возможно, с тем же вкусом: протоколы. Протоколы (интерфейсы на некоторых других языках) - это способ определения набора методов, который принимает эти протоколы для реализации. Однако протокол не обеспечивает реализацию. Это ограничение не позволяет использовать протоколы в качестве точного эквивалента Ruby mixins.

Еще менее короткий ответ: Тем не менее, среда выполнения Objective-C имеет открытый API, который позволяет играть с динамическими функциями языка. Затем вы выходите за пределы языка, но вы можете иметь протоколы с реализацией по умолчанию (также называемые конкретными протоколами). Ответ Владимира показывает один из способов сделать это. В этот момент мне кажется, что вы получаете Ruby mixins в порядке.

Однако я не уверен, что рекомендую это сделать. В большинстве случаев другие шаблоны соответствуют законопроекту, не играя в игры со временем выполнения. Например, у вас может быть под-объект, реализующий смешанный метод (имеет-a вместо is-a). Игра со временем выполнения в порядке, но имеет 2 недостатка:

  • Вы делаете свой код менее читабельным, так как он требует, чтобы читатели знали намного больше, чем язык. Конечно, вы можете (и должны) прокомментировать это, но помните, что любой необходимый комментарий можно рассматривать как дефект реализации.

  • Вы зависите от этой реализации языка. Конечно, платформы Apple на сегодняшний день являются наиболее распространенными для Objective-C, но не забывайте, что Cocotron или GnuStep (или Etoilé) имеют разные режимы работы, которые могут или не могут быть совместимы с Apple в этом отношении.

В качестве побочного примечания я указываю ниже, что категории не могут добавлять состояние (переменные экземпляра) в класс. Используя API runtime, вы также можете снять это ограничение. Однако это выходит за рамки этого ответа.

Длинный ответ:

Две функции 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];
    }
}

Обратите внимание, что певцам в массиве не нужно иметь общий суперкласс. Также обратите внимание, что класс может иметь только один суперкласс, но многие принятые протоколы. Обратите внимание, наконец, что проверка типов выполняется компилятором.

По сути, механизм протокола - это множественное наследование, используемое для шаблона mixin. Это множественное наследование сильно ограничено, потому что протокол не может добавлять новые переменные экземпляра в класс. Протокол описывает только общедоступный интерфейс. В отличие от модулей Ruby он не содержит реализации.

Это больше всего. Однако укажите категории.

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

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

Сегодня нет необходимости использовать категории в качестве протоколов, особенно потому, что официальные протоколы теперь могут объявлять, что некоторые из их методов являются необязательными с ключевым словом @optional или обязательными (по умолчанию) с помощью @required.

Категории по-прежнему полезны для добавления определенного поведения домена к существующему классу. NSString является общей целью для этого.

Также интересно отметить, что большинство (если не все) объектов NSObject фактически объявлены в протоколе NSObject. Это означает, что это не очень важно использовать NSObject как обычный суперкласс для всех классов, хотя это все еще обычно делается по историческим причинам и хорошо... потому что для этого нет недостатка. Но некоторые системные классы, такие как NSProxy, не являются NSObject.

Ответ 2

Бесстыдный плагин: ObjectiveMixin

Для использования во время выполнения Objective-C возможности добавления методов в класс во время выполнения (в отличие от категорий, которые только время компиляции). Проверьте это, он работает очень хорошо и аналогично Ruby mixins.

Ответ 3

Вы можете буквально смешивать код с помощью #include. Это нецелесообразно и противоречит всем религиям в objective-c, однако прекрасно работает.

Пожалуйста, не делайте этого в производственном коде.

, например, в файле:

MixinModule.header(не следует компилировать или копировать в цель)

-(void)hello;

MixinModule.body(не следует компилировать или копировать в цель)

-(void)hello{
    NSLog(@"Hello");
}

в классе mixin:

@interface MixinTest : NSObject
#include "MixinModule.header"
@end

@implementation MixinTest
#include "MixinModule.body"
@end

пример использования:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]){
    @autoreleasepool {
        [[[MixinTest new] autorelease] hello];
    }
    return 0;
}

Пожалуйста, не делайте этого в производственном коде.

Ответ 4

Это мой прием по внедрению Mixins в Objective-C, без непосредственного использования времени выполнения Objective-C. Может быть, это кому-то полезно: fooobar.com/info/197467/...