3

実際の例を挙げると、基本クラスはVehicleであり、具象クラスはTwoWheelerとFourWheelerであるとします。現在、車両のタイプ(TwoWheelerまたはFourWheeler)は、基本クラスの車両によって決定されます。alloc-initメソッドを使用してTwoWheeler/FourWheelerのインスタンスを作成すると、以下のようなスーパー実装を呼び出して、Vehicleクラスで定義された共通プロパティの値を設定し、これらのプロパティの1つは、タイプが実際にタイプかどうかを決定するタイプです。 TwoWheelerまたはFourWheelerです。

   if (self = [super initWithDictionary:dict]){
     [self setOtherAttributes:dict]; 
      return self; 
    }

今、私が車のコレクションを手に入れるとき、それらのいくつかはTwoWheelerであり、他はFourWheelerである可能性があります。したがって、このようなTwoWheelerまたはFourWheelerのインスタンスを直接作成することはできません。

Vehicle *v = [[TwoWheeler alloc] initWithDictionary:dict];

基本クラスのインスタンスを作成し、タイプがわかったら、タイプに応じて子クラスのインスタンスを作成して返す方法はありますか?現在の実装では、具象クラスからスーパー実装を呼び出すため、無限ループになります。

どの具象クラスを事前にインスタンス化する必要があるかわからない場合、このシナリオを処理するための完璧な設計は何でしょうか?

4

2 に答える 2

5

通常、これはファクトリで行われます。

ファクトリを基本クラスの一部にしたい場合、それは問題ありませんが、将来的に問題が発生する可能性があります。Objective Cでは、クラスメソッドは優れたファクトリを作成します。

+ (Vehicle *)vehicleWithDictionary:(NSDictionary *)dict
{
    if ([[dict objectForKey:kVehicleType] isEqualToString:@"TwoWheeler"]) {
        return [[[TwoWheeler alloc] initWithDictionary:dict] autorelease];
    } else if ([[dict objectForKey:kVehicleType] isEqualToString @"FourWheeler"]) {
        return [[[FourWheeler alloc] initWithDictionary:dict] autorelease];
    } else {
        return [[[Vehicle alloc] initWithDictionary:dict] autorelease];
    }
}

工場はVehicleクラスの一部であり、そのように使用できます。

// Instead of [[Vehicle alloc] initWithDictionary:dict]
Vehicle *vehicle = [Vehicle vehicleWithDictionary:dict];

アップデート

私は求められたことを行う方法を思いついた。それがなぜそんなに悪い考えであり、なぜあなたがそれを決してしてはいけないのかという輝かしい例として役立つようにしましょう。

- (id)initWithDictionary:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
        // If override is in the dictionary, then it mustn't try to call the subclass.
        if (![dict objectForKey:kOverride]) {
            NSMutableDictionary *overrideDict = [NSMutableDictionary dictionaryWithDictionary:dict];
            [overrideDict setObject:@"override" forKey:kOverride];

            if ([[dict objectForKey:kVehicleType] isEqualToString:@"TwoWheeler"]) {
                [self release];
                return [[[TwoWheeler alloc] initWithDictionary:overrideDict] autorelease];
            } else if ([[dict objectForKey:kVehicleType] isEqualToString @"FourWheeler"]) {
                [self release];
                return [[[FourWheeler alloc] initWithDictionary:overrideDict] autorelease];
            }
        }

        // init as normal
    }

    return self;
}
于 2012-07-03T21:05:55.067 に答える
2

抽象ファクトリを使用する必要があります次のように、クラスVehicleにはcreateInstanceというメソッドがあり、このメソッドには、例を考慮して何を作成するかを決定するパラメータがあります。

+ (Vehicle*) createInstance:(int)numberOfWheels
{
    if(numberOfWheels == 2)
    {
        return [[TwoWheeler alloc] init];
    }
    else
    {
        return [[FourWheeler alloc] init];
    }

    return nil;
}

あなたはそれをこのように呼ぶでしょう

Vehicle *v = [Vehicle createInstance:2];
于 2012-07-03T21:09:58.283 に答える