【问题标题】:Using constants in abstract Objective-C classes?在抽象的 Objective-C 类中使用常量?
【发布时间】:2012-02-04 01:13:33
【问题描述】:

首先,让我澄清一下,我知道在 Objective-C 中不能有实际的抽象类。当我说抽象时,我的意思是我没有创建该类的任何实例,而只是将其用作继承的基类。

我的抽象类包含一个 NSInteger。从这个抽象类继承的所有类都需要使用这个整数。一旦设置, NSInteger 将永远不会改变。 NSInteger 的值虽然会因派生类而异。由于它永远不会改变,我想将变量设为 const。但问题是,如果我将其设为 const,我将不得不在实例化时设置该值。因此我必须在基本抽象类中设置值 - 但是我不能根据它存在的派生类调整值。

我意识到这很难理解,所以我创建了一些基本的伪代码。我以 NSString 为例,但在我的程序中它是一个 NSInteger:

Class animal: const NSString soundItMakes = "Sound" //the constant integer
//since soundItMakes is const I have to set it upon instantiation even though it doesn't make sense in the base class

Class dog: animal //derives from animal. Needs to change the const soundItMakes to fit a dog however since it was already set in animal, the base class, I can't really change it

Class cat: animal //derives from animal. Needs to change the const soundItMakes to fit cat however since it was already set in animal, the base class, I can't really change it.

我不想从基类中删除变量,而是将它放在每个派生类中,也不想让它成为非常量。有没有人看到这个解决方案?我知道这很令人困惑,所以如果需要更多信息,请随时询问。

我在 Mac OS X Snowleopard 的 Xcode 3.2.6 中使用 Cocoa。

【问题讨论】:

  • 为什么不在你的超类上定义一个只读属性,然后每个子类都可以实现getter方法来返回他们需要的东西。我认为这将是规范的 OO 方式,除非我完全错过了您的观点。
  • 为什么它应该是一个变量?是什么阻止你创建一个返回它的方法?

标签: objective-c macos cocoa oop inheritance


【解决方案1】:

通常我会用方法而不是 ivar 来解决这个问题。

@interface Animal : NSObject
+ (NSString *)soundItMakes;
@end

@implementation Animal
+ (NSString *)soundItMakes {
  NSAssert(NO, @"Abstract");
}
@end

@implementation Dog
+ (NSString *)soundItMakes {
  return @"bark";
}

【讨论】:

    【解决方案2】:

    首先:在这种情况下,我可能只使用Animal 协议。

    第二:如果你真的想要一个类的变量,这里有一种方法(你可以适应你正在使用的编译器版本):

    @interface MONAnimal : NSObject
    {
    @private
      int animalCode;
      NSString * soundItMakes;
    }
    
    // designated initializer -- treat as protected
    - (id)initWithAnimalCode:(int)inAnimalCode soundItMakes:(NSString *)soundItMakes;
    
    ... just don't declare setters for animalCode or soundItMakes!
    
    @end
    

    然后你会说:

    @interface MONMoonBear : MONAnimal
    @end
    
    @implementation MONMoonBear
    
    - (id)init
    {
      return [super initWithAnimalCode:MONAnimalCode_MoonBear soundItMakes:@"Eating Garlic and Berries"];
    }
    
    @end
    

    还有一些空白需要填补 - 但这是朝着一种方法的方向推进。

    【讨论】:

    • +1 在某些情况下这是一个很好的方法(我通常使用类方法,但这种方法有其用途)。从这个答案中更重要的一点是建议将Animal 设为@protocol。这是一个经常被忽视的解决方案。
    • +1 给你的 - 如果你没有打败我,我会补充说 :)
    【解决方案3】:

    使soundItMakes 成为在子类中被覆盖的方法或@property(readonly)。如果每个类的值不同,你别无选择,只能在每个类中重新定义。

    // Animal.h
    @interface Animal : NSObject
    - (NSString *)soundItMakes;
    @end
    
    // Animal.m 
    @implementation Animal
    - (NSString *)soundItMakes
    {
        // Throw exception, assert, etc.
        // This will force you to implement the subclass
        return (nil);
    }
    
    // Cat.h
    @interface Cat : Animal
    @property(readonly) NSString *soundItMakes;
    @end
    
    // Cat.m
    @implementation Cat
    @synthesize soundItMakes = _soundItMakes;
    
    - (Cat *)init {
       NSString * const soundMade = @"Meow";
    
        self = [super init];
        if (self != nil)
            _soundItMakes = soundMade;
        return (self);
    }
    @end
    

    【讨论】:

    • 请注意const NSString * 是没有意义的。你的意思是NSString * constNSString 本质上是不可变的,所以前者不做任何事情。后者可防止 soundMade 被重新分配给另一个对象,这就是您的实际意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 2012-06-28
    • 2016-03-17
    • 1970-01-01
    相关资源
    最近更新 更多