Наследование / советы по проектированию в Objective-C - PullRequest
1 голос
/ 29 февраля 2012

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

У нас есть объекты данных, которые извлекаются извеб-сервис, и я пытаюсь построить для них иерархию, но я изо всех сил.

Я подумал, что мой базовый класс должен называться DataEntity, и он определяет абстрактное свойство с именем EntityId и реализует метод хешированияна основе entityId.

Любой объект, извлеченный из веб-службы, может быть реализован одним из двух способов: путем передачи NSDictionary сущности и предоставления ему возможности использовать его в качестве источника данных или путем передачи словаря.объекту и позволяя ему инициализировать свои собственные элементы данных из словаря.Я назвал эти два типа объектов DictionaryBackedDataEntity и ConcretedDataEntity.Таким образом, моя иерархия будет выглядеть так:

DataEntity -> DictionaryBackedDataEntity  
           -> ConcreteDataEntity

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

Итак, моя иерархия будет выглядеть так:

DataEntity -> DictionaryBackedDataEntity -> DictionaryBackedPerson <Person>
                                         -> DictionaryBackedAnimal <Animal>
           -> ConcreteDataEntity         -> ConcretePerson <Person>
                                         -> ConcreteAnimal <Animal>

Теперь, если честно, я не уверен, должен ли я делать вышеуказанное или что-то вроде следующего:

DataEntity -> PersonEntity      -> DictionaryBackedPerson
                                -> ConcretePerson
           -> AnimalEntity      -> DictionaryBackedAnimal
                                -> ConcreteAnimal

В приведенном выше описании PersonEntity и AnimalEntity были бы абстрактными классами, и поэтому экземплярыэто могут быть словарь DictionaryBacked или конкретный экземпляр.

У кого-нибудь есть опыт или рекомендации, как мне подходить к этому?Я, кажется, хожу по кругу и не могу принять решение ...

С уважением, N

Ответы [ 3 ]

2 голосов
/ 29 февраля 2012

Я определенно НЕ создал бы иерархию наследования, которую вы упомянули.Вы хотите создать наследование на основе поведения класса, а не базовой реализации его внутренних данных.Вы получите взрыв классов, когда добавите больше классов, которые наследуются от этих баз, и / или добавите больше базовых реализаций.Представьте, что позже у вас есть 3 типа базовых классов: один использует словарь, один передает его словарь, но использует свойства и поля, а третий использует другой объект или документ XML или что-то еще.Тогда, если вам нужны классы Персона, Животное и Вещи, вы в итоге получите 9 разных классов.DictionaryBackedPerson, ConcreteBackedPerson, ObjectXmlBackedPerson и т. Д. И т. Д.

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

2 голосов
/ 29 февраля 2012

Почему бы просто не иметь единственный класс DataEntity, который хранит значения своих свойств в словаре?Я думаю, что вам, вероятно, не нужно (и, вероятно, не нужно) различать между ConcreteDataEntity и DictionaryBackedDataEntity.

@interface DataEntity
@property ( nonatomic, retain ) NSMutableDictionary * properties ;
@end

@implementation DataEntity
@synthesize properties ;

@end

@interface Animal : DataEntity
@property (nonatomic) NSUInteger numberOfLegs ;

-(id)initWithDictionary:(NSDictionary*)dict
{
    if (( self = [ super init ]))
    {
        self.properties = dict ;
    }

    return self ;
}
@end

@implementation Animal

-(void)setNumberOfLegs:(NSNumber*)n
{
    [ self.properties setValue:n forKey:@"numberOfLegs" ] ;
}

-(NSNumber*)numberOfLegs
{
    return [ self.properties valueForKey:@"numberOfLegs" ] ;
}

@end

В качестве начала ... Вы можете сэкономить немного печати, используянекоторые из наиболее динамичных функций Obj-C здесь ... Смотрите здесь: https://github.com/davedelong/Demos/tree/master/DynamicStorage

0 голосов
/ 29 февраля 2012

Нет ничего плохого в любом подходе из предоставленной вами информации.Но из того, что я вижу, есть две школы мысли.

Первый - использовать технический подход, который является вашим первым примером, в котором вы используете DictionaryBackedDataEntity и ConcreteDataEntity ,Это где ваши классы представляют, как вещи были реализованы.Я видел много такого подхода и вообще говоря, я на самом деле не фанат.Как только ваш код станет больше и задействует больше классов, у этого подхода могут возникнуть проблемы с ясностью, поскольку он представляет не область приложения, а область реализации.то есть.в итоге вы получите множество (даже сотен) классов, построенных вокруг их реализаций, что затруднит понимание того, что они делают для вашей программы.

Второй подход ( PersonEntity и AnimalEntity ), я думаю, более практичный подход, потому что он говорит о контексте ваших приложений и, просто взглянув на имена, вы сразу понимаете, для чего они нужны.В коде простота и понятность ускоряют разработку и упрощают обслуживание.

Но настоящая правда, я думаю, в том, что вам, вероятно, понадобится сочетание обоих подходов в вашей кодовой базе.Часто вам необходимо разрабатывать небольшие и абстрактные классы, которые не обязательно проявляются непосредственно в вашей проблемной области, но имеют большое значение для предоставления инфраструктурного кода, который поддерживает другие классы.Это хорошие кандидаты для именования, основанные на их технических аспектах.Кроме того, это код, который можно разделить на отдельный проект и построить как основу для использования в нескольких приложениях.

Наконец, выбранный вами дизайн будет также зависеть от кода реализации.Например, в зависимости от внутренних элементов ваших сущностей, вы можете использовать первый подход, но изменить его так, чтобы Person и Animal были категориями для DataEntry, а не другой слой классов.

Мой последний совет - не зацикливаться на том, что делать.Выберите тот, который вам наиболее удобен, и продолжайте.Если на более позднем этапе он по какой-то причине окажется менее оптимальным, вы можете выполнить рефакторинг в другой дизайн.Если ничего другого, вы узнаете немного о том, как вы относитесь к коду.

...