Objective-C是否像Ruby一样支持Mixin? [英] Does Objective-C support Mixin like Ruby?

查看:96
本文介绍了Objective-C是否像Ruby一样支持Mixin?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Ruby中,有模块,您可以通过混入"模块来扩展类.

In Ruby, there's Modules and you can extend a class by "mixing-in" the module.

module MyModule
  def printone
    print "one" 
  end
end

class MyClass
  include MyModule
end

theOne = MyClass.new
theOne.printone 
>> one

在Objective-C中,我发现我有一组通用方法,我希望一些Class可以继承".在不创建公共类并从该公共类中派生所有其他方法的情况下,我还能通过哪些其他方式实现这一目标?

In Objective-C, I find that I have a set of common methods that I want a number of Class to "inherit". What other ways can I achieve this without creating a common class and deriving all from that common class?

推荐答案

编辑:添加了一些更改,因为有些人认为我对Objective-C的局限性负责.

Edit: changes added because some people feel I am responsible for the limitations of Objective-C.

简短答案:您不能. Objective-C没有等效的Ruby mixins.

Short answer: you can't. Objective-C doesn't have the equivalent of Ruby mixins.

简短回答:Objective-C确实具有相同的风味:协议.协议(某些其他语言的接口)是一种方法,用于定义采用该协议的类正致力于实现的一组方法.协议虽然没有提供实现.这种局限性阻止了使用协议作为与Ruby mixins完全等效的方法.

Slightly less short answer: Objective-C does have something with arguably the same flavour: protocols. Protocols (Interfaces in some other languages), are a way to define a set of methods an class that adopts that protocols is committing to implementing. A protocol doesn't provide an implementation though. That limitation prevents using protocols as an exact equivalent to Ruby mixins.

答案甚至更少::但是,Objective-C运行时具有公开的API,可让您使用该语言的动态功能.然后您便跳出了语言的范围,但是您可以拥有带有默认实现的协议(也称为具体协议).弗拉基米尔的答案显示了一种方法.到那时,在我看来,您可以正常使用Ruby mixins.

Even less short answer: However, the Objective-C runtime has an exposed API that lets you play with the dynamic features of the language. Then you step outside the language, but you can have protocols with default implementations (also called concrete protocols). Vladimir's answer shows one way to do that. At that point it seems to me you get Ruby mixins alright.

但是,我不确定我会建议这样做.在大多数情况下,无需在运行时玩游戏即可使用其他模式.例如,您可以有一个子对象来实现混合方法( has-a 代替 is-a ).可以运行运行时,但是有两个缺点:

However, I am not sure I would recommend doing that. In most cases, other patterns fit the bill without playing games with the runtime. For example, you can have a sub-object that implement the mixed-in method (has-a instead of is-a). Playing with the runtime is OK, but has 2 drawbacks:

  • 您使代码的可读性降低,因为它要求读者比语言了解更多.当然可以(并且应该)对其进行注释,但是请记住,任何必要的注释都可以视为实现缺陷.

  • You make your code less readable as it requires readers to know a lot more than the language. Sure you can (and should) comment it, but remember that any necessary comment can be seen as an implementation defect.

您依赖语言的 that 实现.当然,Apple平台是迄今为止Objective-C最常见的平台,但不要忘记Cocotron或GnuStep(或Etoilé)具有不同的运行时,在这方面它们可能与Apple兼容,也可能不兼容.

You depend on that implementation of the language. Sure, Apple platforms are by far the most common ones for Objective-C but don't forget Cocotron or GnuStep (or Etoilé) which have different runtimes, which may or may not be compatible with Apple's on that respect.

作为一个补充说明,我在下面声明类别不能将状态(实例变量)添加到类中.通过使用运行时API,您也可以解除该限制.但是,这超出了此答案的范围.

As a side note, I state below that categories cannot add state (instance variables) to a class. By using the runtime API, you can lift that limitation too. This is beyond the scope of this answer however.

详细答案:

Objective-C的两个功能看起来很可能是候选对象:类别和协议.如果我正确地理解了这个问题,那么类别并不是这里的正确选择.正确的功能是协议.

Two Objective-C features look like possible candidates: categories and protocols. Categories are not really the right choice here, if I understand the question properly. The right feature is a protocol.

让我举个例子.假设您希望一堆类具有称为唱歌"的特定功能.然后定义一个协议:

Let me give an example. Suppose you want a bunch of your classes to have a specific ability called "sing". Then you define a protocol:

@protocol Singer
    - (void) sing;
@end

现在,您可以声明自己的任何类都通过以下方式采用该协议:

Now you can declare that any of your own classes adopts the protocol the following way:

@interface Rectangle : Shape <Singer> {
    <snip>
@end

@interface Car : Vehicle <Singer> {
    <snip>
@end

通过声明他们采用了协议,他们致力于实现sing方法.例如:

By declaring that they adopt the protocol they commit themselves to implementing the sing method. For example:

@implementation Rectangle

- (void) sing {
    [self flashInBrightColors];
}

@end

@implementation Car

- (void) sing {
    [self honk];
}

@end

然后使用这些类,例如:

Then you use those classes for example like this:

void choral(NSArray *choir) // the choir holds any kind of singer
{
    id<Singer> aSinger;
    for (aSinger in choir) {
        [aSinger sing];
    }
}

请注意,数组中的歌手不需要具有公共的超类.还要注意,一个类只能有一个超类,但是可以采用许多协议.最后注意,类型检查由编译器完成.

Notice that the singers in the array don't need to have a common superclass. Notice also that a class can have only one superclass, but many adopted protocols. Notice finally that type checking is done by the compiler.

实际上,协议机制是用于混合模式的多重继承.多重继承受到严格限制,因为协议无法将新的实例变量添加到类中.协议仅描述采用者必须实施的公共接口.与Ruby模块不同,它不包含实现.

In effect, the protocol mechanism is multiple inheritance used for the mixin pattern. That multiple inheritance is severely limited because a protocol cannot add new instance variables to a class. A protocol only describes a public interface adopters must implement. Unlike Ruby modules it does not contain an implementation.

最重要的是.但是,让我们提及类别.

That's the most of it. Let's mention categories however.

类别不是在尖括号中声明,而是在括号之间声明.不同之处在于,可以为现有类定义一个类别,以在不对其进行子类化的情况下对其进行扩展.您甚至可以为系统类这样做.您可以想象,可以使用类别来实现类似于mixin的功能.长期以来,这种方式通常用作NSObject(继承层次结构的典型根)的类别,以至于它们被称为非正式"协议.

A category is declared not in angle brackets, but between parenthesis. The difference is that a category can be defined for an existing class to expand it without subclassing it. You can even do so for a system class. As you can imagine, it's possible to use categories to implement something similar to mixin. And they were used that way for a long time usually as category to NSObject (the typical root of the inheritance hierarchy), to such an extent that they were called "informal" protocols.

这是非正式的,因为1-编译器不执行类型检查,并且2-实施协议方法是可选的.

It's informal because 1- no type checking is done by the compiler, and 2- implementing the protocol methods is optional.

今天没有必要使用类别作为协议,尤其是因为正式协议现在可以声明其某些方法使用关键字@optional是可选的,或者使用@required要求(默认).

There is no need today to use categories as protocols, especially because the formal protocols can now declare that some of their methods are optional with the keyword @optional or required (the default) with @required.

类别对于将某些特定于域的行为添加到现有类中仍然很有用. NSString是该目标.

Categories are still useful to add some domain specific behavior to an existing class. NSString is a common target for that.

要指出的是,大多数(如果不是全部)NSObject工具实际上是在NSObject协议中声明的.这意味着使用NSObject作为所有类的通用超类并不是真正令人信服,尽管出于历史原因仍然经常使用NSObject,但是...因为这样做没有缺点.但是某些系统类(例如NSProxy)不是 NSObject.

It's also interesting to point out that most (if not all) of NSObject facilities are in fact declared in a NSObject protocol. This means that it's not really compelling to use NSObject as a common superclass for all classes, though this is still commonly done for historical reasons, and well... because there is no drawback for doing so. But some system classes, such as NSProxy, are not NSObject.

这篇关于Objective-C是否像Ruby一样支持Mixin?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆