【问题标题】:Abstract class in Objective-CObjective-C 中的抽象类
【发布时间】:2012-12-07 18:11:25
【问题描述】:

我需要你的帮助。 Objective-C 中的以下问题:

// Robot.h
@protocol RobotProtocol <NSObject>
    -(void)doWork;
@end

@interface Robot : NSObject 


// Rob1 sublass of class Robot
// rob1.h
@interface Rob1 : Robot <RobotProtocol>

// rob1.m
@implementation
-(void)doWork
{
    // print 'robot 1'
}


// Rob2 sublass of class Robot
// rob2.h
@interface Rob2 : Robot <RobotProtocol>

// rob2.m
@implementation
-(void)doWork
{
    // print 'robot 2'
}



// Task.h
@interface Task : NSObject
{
    Robot *rob;
}


// Task.m
@implementation
- (id)init
{
    if ([super init]) {
        rob = [[Rob1 alloc] init]; // or Rob2 !!
    }
    return self;
}

-(void)doSomething
{
    [rob doWork]; // how to make sure, that this is implemented, depending on Rob1 or Rob2
}

Robot及其子类应该如何实现,Robot *rob可以是Robotrob1rob2...的子类之一,并且可以调用方法doWork:(BOOL)val;?我的第一个想法是把Robot实现为一个抽象类,可惜Objective-C中没有抽象类……

目前我正在使用协议,但我没有信心。因为不确定doWork是否实现,编译器报错

“机器人”可能不会响应“doWork”

感谢您的想法。

【问题讨论】:

  • 你能发布你完整的Objective C代码吗?既定义又使用?
  • 您是否尝试过使用错误断言实现方法,以便它们在运行时触发?不如编译时检查好,但至少可以强制你重写。
  • 在init方法中抛出异常。

标签: objective-c protocols abstract-class cocoa-design-patterns


【解决方案1】:

协议应该可以工作。

@protocol RobotProtocol <NSObject>
@required
- (void)doWork:(BOOL)flag;
@end

@interface Robot1 : NSObject <RobotProtocol>
@end

@implementation Robot1
- (void)doWork:(BOOL)flag
{
}
@end

通过id&lt;RobotProtocol&gt; 调用Robot1 的单元测试

- (void)testRobot
{
    id<RobotProtocol> robot = [[Robot1 alloc] init];
    [robot doWork:YES];
}

更新

查看您的代码后,@interface Robot : NSObject 应该是 @interface Robot : NSObject &lt;RobotProtocol&gt;。问题是你根本不需要@interface Robot : NSObject &lt;RobotProtocol&gt;。你可以使用id&lt;RobotProtocol&gt;。这是您的抽象类的名称。

【讨论】:

  • 谢谢。我试过这个,但我的错误是在我的任务类中声明id&lt;RobotProtocol&gt; *robot(带*),这是行不通的!
【解决方案2】:

正如许多人所说,Objective-C 中没有抽象类。我个人选择 cmets + 运行时检查。像这样的代码:

@interface Abstract : NSObject {
}

// Abstract method
- (Foo*)doSomething;

@end

@implementation Abstract

// Abstract method
- (Foo*)doSomething {
  [_self doesntRecognizeSelector:_cmd];
  return nil;
}

@end

如果您真的想使用“抽象”的东西并进行编译时检查,我认为您将不得不使用协议。为此,您需要稍微更改代码。特别是您应该将变量声明为符合协议,id&lt;RobotProtocol&gt;Robot&lt;RobotProtocol&gt;*,具体取决于更适合您的需求:

// Task.h
@interface Task : Robot <RobotProtocol>
{
    id<RobotProtocol> rob;
}

【讨论】:

    【解决方案3】:

    我猜你正在尝试做这样的事情,但没有代码很难说......

    //Robot.h
    {
        -(void)doWork:(BOOL)myBool
    }
    
    //Robot.m
    {
        -(void)doWork:(BOOL)myBool
        {
            if (myBool)
            {
                //do something
            }
            else
            {
                //do something else
            }
        }
    }
    
    
    
    //Task.h
    {
           #include"Robot.h"
    }
    
    //Task.m
    {
                Robot *rob = [[Robot rob] alloc] init];
        [rob doWork:YES];
    }
    

    【讨论】:

      【解决方案4】:

      Objective-C 没有像 java 中那样的抽象类。只需创建一个名为 Robot 的超类并将其子类化.. 您甚至可以通过覆盖 init 并立即销毁自身来阻止实例化该类(尽管我不太确定这种方法的“正确性”..)

      无论如何,这应该不是问题。

      判断某个对象是否响应某个方法的一个方便技巧是使用

      if( [rob respondsToSelector:@selector(doWork:)] ) { [rob doWork:value]; }
      

      这通常用于使协议中的方法成为可选方法,这样当您调用给定对象不存在的方法时,您就不会在运行时出错。

      【讨论】:

      • 感谢您的想法,但应该在编译时检查。
      【解决方案5】:

      尝试调用 doWork 的任何方法都知道 RobotProtocol 协议吗?您可能需要导入包含它的任何头文件。

      对于它的价值,做你想做的事情的公认方法是只声明超类是什么(机器人),声明和实现具有空主体的方法(如果它们没有被子类覆盖,可能会抛出 NSException)并创建你的子类(SubRobot,或者你有什么)。协议更多的是不同类型的类可以实现一些已知的方法,而不是用作事实上的抽象超类。

      【讨论】:

        猜你喜欢
        • 2012-11-27
        • 2016-03-17
        • 2012-06-28
        • 1970-01-01
        • 1970-01-01
        • 2010-11-05
        • 1970-01-01
        • 1970-01-01
        • 2013-11-29
        相关资源
        最近更新 更多