Является ли подклассы в Objective-C плохой практикой? - PullRequest
16 голосов
/ 10 мая 2009

После прочтения большого количества блогов, записей на форуме и нескольких документов Apple, Я до сих пор не знаю, является ли разумным расширенное создание подклассов в Objective-C .

Возьмем, к примеру, следующий случай:

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

Итак, после определения того, что наследует из чего, я решил выделить подкласс забвения. И почему я не должен? Учитывая легкость настройки общего Поведение берет с этой моделью, я думаю, что я достиг чего-то ООП предназначены для.

Но, - и это источник моего вопроса - Apple упоминает с использованием делегатов, методов источника данных и неформальных протоколов в пользу подкласса . Это действительно уму непостижимо, почему?

Кажется, есть два лагеря. Те, кто выступает за создание подклассов, те, кто в этом нет. Это зависит от личного вкуса, по-видимому. Мне интересно, каковы плюсы и минусы массового подкласса, а не массового подкласса ?

Если подвести итог, мой вопрос прост: Я прав? А почему или почему нет?

Ответы [ 9 ]

12 голосов
/ 10 мая 2009

Делегирование - это средство использования метода композиции для замены некоторых аспектов кодирования, для которых вы бы в противном случае использовали подкласс. Как таковой, он сводится к давнему вопросу о задаче, которая нуждается в одной большой вещи, которая знает, как много делать, или если у вас свободная сеть специализированных объектов (очень UNIX-модель модели ответственности).

Использование комбинации делегатов и протоколов (для определения того, что делегаты должны делать) обеспечивает большую гибкость поведения и простоту кодирования - возвращаясь к этому принципу подстановки Лискова, когда у вас есть подкласс чтобы быть осторожным, вы не делаете ничего, что пользователь всего класса сочтет неожиданным. Но если вы просто создаете объект делегата, то ответственность за него гораздо меньше, только то, что реализуемые вами методы делегата делают то, к чему призывает этот протокол, за исключением того, что вас не волнует.

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

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

10 голосов
/ 10 мая 2009

Лично я следую этому правилу: я могу создать подкласс, если он соблюдает принцип замены Лискова .

7 голосов
/ 10 мая 2009

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

Одна из причин, по которой я это делаю, заключается в том, что когда вы наследуете реализацию, вы можете столкнуться с проблемами, если переопределите методы, но не будете придерживаться их (иногда недокументированный контракт). Кроме того, я нахожу иерархии классов с трудоемким наследованием реализацией трудными, поскольку методы могут быть переопределены или реализованы на любом уровне. Наконец, при создании подклассов вы можете только расширить интерфейс, вы не можете сузить его. Это приводит к неплотным абстракциям. Хорошим примером этого является java.util.Stack, который расширяет java.util.Vector. Я не должен быть в состоянии рассматривать стек как вектор. Это позволяет потребителю только бегать по интерфейсу.

Другие упоминали принцип замещения Лискова. Я думаю, что использование этого, безусловно, решило бы проблему java.util.Stack, но это также может привести к очень глубокой иерархии классов, чтобы гарантировать, что классы получат только те методы, которые должны иметь.

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

В конце концов, не имеет значения, по какому пути вы идете. Оба вполне приемлемы. На самом деле это больше зависит от того, с чем вам удобнее работать, и с какими платформами вы работаете. Как гласит старая поговорка: «Когда в Риме делай, как римляне».

6 голосов
/ 10 мая 2009

Нет ничего плохого в использовании наследования в Objective-C. Apple использует это совсем немного. Например, в Cocoa-touch деревом наследования UIButton является UIControl: UIView: UIResponder: NSObject.

Я думаю, что Мартин затронул важный момент, упомянув принцип подстановки Лискова. Кроме того, правильное использование наследования требует, чтобы разработчик подкласса имел глубокие знания суперкласса. Если вы когда-нибудь пытались расширить нетривиальный класс в сложной среде, вы знаете, что всегда есть кривая обучения. Кроме того, детали реализации суперкласса часто «просачиваются» в подкласс, что является большой проблемой в @ $ & для сборщиков фреймворков.

Apple решила использовать делегирование во многих случаях для решения этих проблем; нетривиальные классы, такие как UIApplication, предоставляют общие точки расширения через объект-делегат, поэтому у большинства разработчиков есть более легкая кривая обучения и более свободно связанный способ добавления специфического поведения приложения - прямое расширение UIApplication редко требуется.

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

Я часто вижу, как разработчики приложений извлекают уроки из конструкций фреймворка и пытаются применить их к своему коду приложения (это часто встречается в мире Java, C ++ и Python, а также в Objective-C). Хотя хорошо подумать и понять, какой выбор сделали разработчики фреймворков, эти уроки не всегда применимы к коду приложения.

4 голосов
/ 13 октября 2012

Пожалуйста, прочитайте документацию Apple "Добавление поведения в программу Какао" !. В разделе «Наследование из класса какао» см. Второй абзац. Apple четко упоминает, что создание подклассов является основным способом добавления специфического поведения приложения в платформу (обратите внимание, FRAMEWORK ).
Шаблон MVC не полностью запрещает использование подклассов или подтипов. По крайней мере, я не видел эту рекомендацию ни от Apple, ни от других (если я пропустил, пожалуйста, не стесняйтесь указывать мне правильный источник информации об этом). Если вы подклассифицируете классы API только в своем приложении, пожалуйста, продолжайте, никто вас не останавливает, но позаботьтесь о том, чтобы это не нарушало поведение класса / API в целом. Подклассы - отличный способ расширить функциональность API фреймворка. Мы также видим множество подклассов в API-интерфейсах Apple IOS. Как разработчик, нужно позаботиться о том, чтобы реализация была хорошо документирована и не была случайно продублирована другим разработчиком. Это еще одна игра с мячом, если ваше приложение представляет собой набор классов API, которые вы планируете распространять как компонент многократного использования.

ИМХО, вместо того, чтобы расспрашивать, каков наилучший метод, сначала внимательно прочитайте соответствующую документацию, внедрите и протестируйте ее. Сделайте свое собственное суждение. Вы лучше знаете о том, что вы делаете. Другим (как мне и многим другим) легко просто читать материалы из разных источников в Сети и разбрасывать термины. Будь своим собственным судьей, у меня это сработало.

4 голосов
/ 10 мая 2009

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

При работе с API у подклассов есть больше потенциальных ошибок - например. если какой-либо класс в иерархии классов получает новый метод с тем же именем, что и ваше добавление, вы делаете прерывание. А также, если вы предоставляете полезную / вспомогательную функцию типа, есть вероятность, что в будущем что-то похожее будет добавлено к реальному классу, который вы использовали для подклассов, и это может быть более эффективным, и т. Д., Но ваше переопределение скрывает это. 1003 *

3 голосов
/ 10 мая 2009

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

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

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

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

2 голосов
/ 11 мая 2009

Мое впечатление о том, что ADC делает упор на подклассы, больше связано с наследием того, как развивалась операционная система ... в те времена (Mac Classic aka os9), когда c ++ был основным интерфейсом для большинства компьютеров Mac. Инструментарий, создание подклассов было стандартом де-факто для того, чтобы программист мог изменить поведение обычных функций ОС (и это действительно иногда было болью в шее и означало, что нужно быть очень осторожным, чтобы любые и все модификации вели себя предсказуемо и не нарушал стандартное поведение).

Сказав это, МОЕ ВПЕЧАТЛЕНИЕ акцента АЦП против подклассов не выдвигает аргумент в пользу разработки иерархии классов приложения без наследования, НО INSTEAD , чтобы указать, что в новый способ работы (то есть OSX) в большинстве случаев есть более подходящие способы настройки стандартного поведения без необходимости создавать подклассы.

Итак, во что бы то ни стало, спроектируйте архитектуру своей программы-головоломки настолько надежно, насколько это возможно, используя наследование по своему усмотрению!

с нетерпением ждем вашего нового классного приложения-головоломки!

| K <</p>

0 голосов
/ 19 января 2014

Apple действительно, кажется, пассивно препятствует созданию подклассов в Objective-C.

Это аксиома ООП-дизайна, которая способствует созданию композиции по сравнению с реализацией.

...