0

我在 Objective-C 中有一个抽象接口,其中每个子类都需要设置一个属性,然后在init. 我试图避免使用类似这样的重复代码:

接口文件

@interface Shape : NSObject

@property (nonatomic) PropertyType *prop;

- (id)init;
- (void)initProperty;

@end

实施文件

@implementation Shape

- (id)init
{
    if(self = [super init]) {
        [self initProperty];
        [prop doSomething];
    }
    return self;
}

- (void)initProperty
{
}

@end

我的问题是每个子类都需要传递一组不同的参数initProperty才能正确实现该方法:

@implementation Rectangle

- (void)initPropertyWithRect:(CGRect)rect
{
    prop = [RectangleStuff rectangleWithRect:rect];
}

@end

@implementation Circle

- (void)initPropertyWithRadius:(CGFloat)radius
{
    prop = [CircleStuff circleWithRadius:radius];
}

@end

有没有一种干净的方法来做我想要在 Objective-C 中做的事情?到目前为止,我的选择似乎是:

  1. 创建一个“财产包”,然后传递一个NSDictionary.
  2. 复制[property doSomething];每个子类中的代码。
  3. 以某种方式将工厂对象传递给 init,并让工厂对象创建prop。这种方法似乎最干净,但我需要工厂对象以某种方式将矩形和/或半径保持为内部状态,这对我来说似乎并不干净。

有什么想法吗?

4

3 回答 3

1

首先,我觉得有必要提到你的 init 函数除了初始化对象之外不应该做任何事情。也就是说,每条规则都有时间和地点被打破,所以我会提供我能提供的建议。

您的 init 函数与任何其他函数没有什么不同。你可以在调用 super 之前和之后做一些事情。虽然通常不鼓励,但这将是一个很好的地方。您的子类中的 init 现在看起来像这样:

- (id)init
{
    self.myProperty = value;
    self = [super init];
    if (self) {
        // more init stuff
    }
    return self;
}
于 2013-11-22T00:45:49.263 回答
1

我可能会选择#2(保持简单)。如果属性只设置一次(在子类的 init 方法中),您可以覆盖超类中的属性设置器方法,并在那里做额外的事情。

未经测试的代码:

- (void)setProp:(PropertyType *)prop
{
    _prop = prop; // (Assuming ARC)
    [_prop doSomething];
}
于 2013-11-21T23:03:21.913 回答
0

我最终使用了其他两个答案中建议的变体:

形状.h

@interface Shape : NSObject

@property (nonatomic) PropertyType *prop;

- (id)initWithProperty:(PropertyType *prop);

@end

形状.m

@implementation Shape

- (id)initWithProperty:(PropertyType *)prop
{
    if(self = [super init]) {
        _prop = prop;
        [_prop doSomething];
    }
    return self;
}

@end

矩形.m/圆形.m

@implementation Rectangle

- (void)initWithRect:(CGRect)rect
{
    return [self initWithProperty:[RectangleStuff rectangleWithRect:rect]];
}

@end

@implementation Circle

- (void)initWithRadius:(CGFloat)radius
{
    return [self initWithProperty:[CircleStuff circleWithRadius:radius]];
}

@end
于 2013-12-20T02:47:25.620 回答