Objective-c - рекомендуемый шаблон для каскадного принятия решений в кластере классов

Я хотел бы создать "многоуровневый" кластер классов, чтобы каждый "конкретный" класс мог возвращать более конкретный экземпляр при выполнении определенных критериев.

Например, в базовом классе:

@interface BaseClass : NSObject  // this is the public API of the service

+(instancetype)initWithData:(Data *)data;
// common interface of all the specific implementations..
...
...

@end


@implementation BaseClass

// basically implementing the "cluster"
+(instancetype)initWithData:(Data *)data {
  // testing some conditions to decide on the more specific version of the class to return...
  if (data.condition == condition1) {
     return [[SomeClassOne alloc] initWithData:data];
  }
  if(data.condition == condition2) {
     return [[SomeClassTwo alloc] initWithData:data];
  }
  ... 
  // have many types which could be returned 
}


// an example of a specific instance that should be returned from the cluster - all of these classes are "private" implementations of the base class
@implementation SomeClassOne

-(instancetype)initWithData:(Data *)data {
  self = [super initWithData:data];
  // all was good until a new optimization came about...
  // now this instance can refine the class cluster even better
  // what I would want is a way to do:
  self = [[SomeClassOne_EvenBetterVersion alloc] initWithData:data];
  // but this would be bad - and would cause recursion if the new version inherits this version...
}
@end

Я не хочу постоянно добавлять новые условия в базовый класс (большое утверждение "если"), потому что условия становятся очень специфичными для конкретных классов - в основном это оптимизация, связанная с новыми возможностями.

Есть ли лучший шаблон для этого?

Я думал о создании метода класса в каждом подклассе, который бы делал дополнительные проверки - но это становится действительно неловким, вызывая [Subclass initWithData:data] в каждом подклассе

1 ответ

Несколько вещей, которые могут улучшить это:

1) Переопределите allocWithZone: чтобы ваш BaseClass возвращал единичный экземпляр BaseClass. Это предотвращает дополнительные выделения объектов. InitWithData: метод BaseClass вернет вам реальный экземпляр.

2) Структурируйте или преобразуйте параметр Data таким образом, чтобы облегчить поиск в словаре, чтобы получить конкретный класс реализации. Убедитесь, что в initWithData:

Создайте структуру статически в +initialize (или динамически всякий раз, когда), которая выглядит следующим образом:

static_dictionary = @{ @"Some string or hashable condition" : [CoolSubclass class],
                       @"Condition2" : [CoolerSubclass class] };

Теперь в initWithData: у вас есть постоянное время поиска вашего типа и чистого кода.

Class my_type = [static_dictionary objectForKey: transformated_data_condition];
if(my_type == Nil) { // throw? return nil? }
return [[my_type alloc] initWithData: data];

Теперь становится легко повторять этот процесс - возможно, CoolerSubclass - это еще один кластер классов, имеющий собственный словарь типов и метод тестирования.

Другие вопросы по тегам