Управление объектами разных классов в одном NSMutableArray - PullRequest
0 голосов
/ 16 марта 2012

Я ищу совет о том, является ли это хорошей практикой.Я прошу прощения за подробное объяснение.У меня есть большая сетка координат х, у.Сетка занята объектами разных классов, все с разными методами и данными.Когда пользователь касается координаты сетки, я ищу самый простой способ направить мою программу к правильному методу, в зависимости от типа объекта.

Я буду использовать фигуры как простой способ объяснить, что я делаю.Скажем, у меня есть 2 класса, Circle и Square и родительский класс Shape.

Я добавляю объекты класса Circle и Square в NSMutableArray с именем shapeManager.Когда пользователь касается сетки, я хочу выяснить тип объекта для этой координаты, чтобы я мог перейти к соответствующему методу.

for (Shape *shape in shapeManager) {

  if (shape.type == kCircle) {

    [self circleSelected:shape];

  }

}

-(void)circleSelected:(circle *)circle { }

Когда я делаю это, я переделываю указатель в другой класс?Есть ли минусы в этом?Я просто ищу хороший способ обработки события касания в сетке, когда объект, который живет по этой координате, неизвестен и имеет несколько возможных классов.

Ответы [ 3 ]

0 голосов
/ 16 марта 2012

Как насчет реализации метода selected в подклассах Shape, которые являются классами Circle и Square.Тогда объект может напрямую вызывать метод selected.

for (Shape *shape in shapeManager) {
    [self selected];
}

Реализация круга

@interface Circle: Shape
{
}
@implementation Circle
-(void)selected
{
    // do your circle select stuff here
}

@end

Реализация квадрата

@interface Square: Shape
{
}
@implementation Square
-(void)selected
{
    // do your square select stuff here
}

@end
0 голосов
/ 16 марта 2012

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

В этом другом подходе ваш цикл становится:

for(Shape *shape in shapeManager)
   [shape userSelected];

И, например, Circle получает метод:

@implementation Circle

// override Shape's userSelected and do what a circle needs to do
- (void) userSelected
{
   ...
}

Какой подход вы выберете, зависит от вас, нет правильного ответа как такового , но объектно-ориентированный стиль обычно благоприятствует последнему.

Продолжение комментария

Чтобы перейти от потомка к родителю, вам не нужен приведение, но вы можете включить его - это фундаментальная основа объектно-ориентированных языков на основе наследования, таких как Obj-C.

Переходя в другую сторону, от родителя к ребенку, в Obj-C (a) требуется приведение и (b) должна быть защищена проверка - и то, и другое, потому что вы не знаете, каких, если таковые имеются, детей, которых вы иметь. В Obj-C (а) просто говорит компилятору, что вы думаете вы знаете, и он должен вам доверять, (б) вы проверяете, чтобы убедиться!

Вы делаете (b) с [<obj> isKindOfClass:[<classname> class], который проверяет, имеет ли <obj> тип <classname> или любого из его дочерних элементов; или вы можете использовать isMemberOfClass, который проверяет, имеет ли <obj> тип <classname> , но не любого из его дочерних элементов. Первый чаще используется для легкого расширения (например, вы можете начать с Rectangle как Shape, а затем ввести Square как Rectangle; тест для isMemberOfClass:[Rectangle class] будет YES для обоих Rectangle и Square, в то время как isKindOfClass:[Rectangle class] составляет всего YES для Rectangle).

Явное тестирование обычно не требуется, так как диспетчеризация метода часто включает его - как в [shape userSelected] выше, который будет вызывать соответствующую реализацию userSelected, основанную на фактическом типе shape во время выполнения. Если требуется явное тестирование с использованием тестов и приведений, это можно сделать.

И да, коллекции смешанного типа распространены, на самом деле они являются еще одной из планок объектно-ориентированных языков, основанных на наследовании, таких как Obj-C.

[Примечание: то, чего не хватает Obj-C, которое есть у ряда других языков, - это способ ограничить то, что может содержать коллекция. Например. NSMutableArray может содержать любой объект, в то время как в вашем случае было бы полезно иметь возможность сказать NSMutableArray of Shape, чтобы ограничить его только Shape и его подклассами. C #, Ada и даже C ++ (в той степени, в которой это что-либо обеспечивает) все это обеспечивают. Если вам нужно, вы можете сделать это самостоятельно в Obj-C, см. этот ответ .]

0 голосов
/ 16 марта 2012

Все классы, производные от NSObject, наследуют метод с именем isMemberOfClass:, который проверяет членство в классе с помощью самоанализа. Вы можете найти это полезным для ваших целей.

for (Shape *shape in shapeManager) {

    if ([shape isMemberOfClass:[Circle class]]) {   
        [self circleSelected:(Circle*)shape];
    }
    else if ([shape isMemberOfClass:[Square class]]} {
        [self squareSelected:(Square*)shape];
    }
}

Существует также метод isKindOfClass:, который выполняет аналогичный тест, но также возвращает true, если принимающий объект является подклассом класса, с которым вы тестируете.

...