Недостаток вашего подхода наступит, если вы добавите еще один 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, см. этот ответ .]