【问题标题】:Objective C - Categories and Inheritance - Add method to base and add override to derived classObjective C - 类别和继承 - 将方法添加到基类并将覆盖添加到派生类
【发布时间】:2012-02-23 15:56:09
【问题描述】:

我知道不应使用类别来覆盖它们所扩展的类中的方法。但是,下面的场景呢?

考虑类:

Base.h

#import <Foundation/NSObject.h>

@interface Base: NSObject { NSNumber *n; }
@end

Derived.h

#import "Base.h"

@interface Derived: Base { NSString *s; }
@end

有类别:

Base+Serialize.h

#import "Base.h"

@interface Base (Serialize)
- (NSString*)serialize;
@end

Base+Serialize.m

#import "Base+Serialize.h"

@implementation Base (Serialize)
- (NSString*)serialize
{
    return [NSString stringWithFormat:@"%@", n];
}

@end

派生+序列化.h

#import "Derived.h"

#import "Base+Serialize.h"

@interface Derived (Serialize)
- (NSString*)serialize;
@end

派生+序列化.m

#import "Derived+Serialize.h"

@implementation Derived (Serialize)
- (NSString*)serialize
{
    return [NSString stringWithFormat:@"%@, %@", s, [super serialize]];
}

@end

显然,这是一个人为/简化的示例。但它很好地展示了我想做的事情。本质上,我想为继承层次结构中的多个类提供附加功能。

这是对类别的安全/有效使用吗?有什么陷阱吗?

【问题讨论】:

    标签: objective-c inheritance categories


    【解决方案1】:

    这是使用类别的可接受方式。类别确实将消息添加到类中,因此该消息将像任何其他消息一样工作。这包括继承。

    也许需要注意的一件事是您可能会遇到名称冲突。我不知道运行时如何处理它们,但如果两个类别提供相同的消息,您可能会出现意外行为,因为您期望的消息没有被调用。话虽如此,您可能只想要一个比serialize 更有特色的名称,当然,除非您需要该名称(例如,您有一个非正式协议)。

    【讨论】:

    • 感谢您确认此方法没有任何隐藏问题。这让人放心。你对名字的评论是有效的,我会考虑的。如果很快没有反对意见,我会接受你的回答。
    • 那么问题中的示例会是名称冲突吗?有两个类别实现了一个序列化方法。我们能确定会调用正确的吗?
    【解决方案2】:

    这似乎不是一个很好的对象模型。 Base.h 和 Derived.h 看起来不错。制定一个协议来定义 serialize: 方法而不是一个类别怎么样?这样会干净一些。 Base.h 将表明它将实现协议,而 Derived 可以根据需要覆盖该方法。

    【讨论】:

    • 是的,对于提供的示例,这肯定是可能的。但是,类别有其优势。一方面,它们提供了另一种构建代码的方式,允许您将可选功能保留在原始类之外。或者,假设 Base 和 Derived 由另一个库提供,我不想修改源代码。
    • 这个其他库是用 c++ 编写的吗?在objective-c中,所有方法都可以在派生类中被覆盖,尽管它是以前的实现。但是,如果 lib 是 c++ 中的,那么使用 Objective-c++ 语法覆盖以前的虚拟方法是有意义的。
    • @RaphaelAyres:如果我理解正确,您建议在库类的子类中提供附加方法。但是,这在现有继承层次结构的情况下是不可行的。据我所知,没有办法创建MyBaseMyDerived 并将它们注入到层次结构中,以便MyDerived &lt; Derived &lt; MyBase &lt; Base
    • 但是,如果库为您提供了一个虚拟接口来实现,那么您可以基于相同的接口创建自己的类,并在它们具有与另一个相同的签名后注入回库中类。当然,如果你想添加功能,它不适用于库,但如果你只是想给个人实现,虚拟接口是要走的路。请记住,如果您的库是 C++ 中的,如果它是 Objective-c 中的,请记住这可以工作,正如答案所指出的那样,以相同的方式使用协议......
    猜你喜欢
    • 2013-09-21
    • 2011-05-14
    • 2020-02-23
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多