Я действительно очарован концепцией протокола-ориентированного программирования в Swift, и из-за этого я перемещаю старый проект, который я создал в прошлом году (который первоначально был основой OOP) для POP.Каков правильный способ реализации свойств по умолчанию при выполнении по умолчанию протоколов в Swift?
На этом этапе проблемы, с которыми я столкнулся, могут быть связаны с тем, что я неправильно понимаю POP, или у Swift 2.0 Betas нет всего, чтобы создать действительно основанную на протоколах фреймворк (не очень-то). Возможно, я ошибаюсь в некоторых аспектах POP).
Прототип-ориентированное программирование - это совершенно новая парадигма программирования, представленная миру менее месяца назад, поэтому в ней мало написанного контента (only tutorial, который я нашел по этой теме, не затрагивает проблему, я и видео WWDC тоже не было).
В любом случае, я либо делаю что-то не так, либо один из недостатков протокола-ориентированного программирования заключается в том, что вы обязаны повторять много кода. Показательный пример:
У меня есть следующий протокол, который обладает многими свойствами, а также соответствует Equatable
протокола:
protocol MediaType : Equatable {
/// MARK: - Properties
/// The ID of the media, as assigned by MyAnimeList.
var ID: Int { get }
/// The title of the media.
var title: String { get }
/// Other titles by which this anime may be commonly known (only available in details requests).
var otherTitles: (synonyms: [String], english: [String], japanese: [String])? { get }
/// The global ranking of the title (only available in anime details requests).
var rank: Int? { get }
/// Rank of the title based on popularity (number of people adding title to the list) (only available in details requests).
var popularityRank: Int? { get }
/// URL to a representative image of the title. Usually a "cover" image.
var imageURL: String { get }
/// A list of adaptations of this media, or other media on which this media is based (only available in details requests).
var adaptations: Relationships { get }
/// The user's rating of the media.
var memberScore: Float { get }
/// Number of MyAnimeList members that that added the title to their list (only available in details requests).
var membersCount: Int? { get }
/// The number of MyAnimeList members that have this title on their favorites list (only available in details requests).
var favoritedCount: Int? { get }
/// A short HTML-formatted description of the media.
var synopsis: String { get }
/// A list of genres for this title (only available in details requests).
var genres: [String]? { get }
/// Popular tags for the title as assigned by MyAnimeList members (only available in details requests).
var tags: [String] { get }
}
В оригинальной версии моей структуры, этот протокол был класс называется Media
, и два другие классы, унаследованные от него. Таким образом, они получили все эти свойства бесплатно.
Но это не похоже, что я могу передать свои объекты, соответствующие этому протоколу, по умолчанию (а именно, геттеры) для этих свойств?
Первое, что я пытался, что просто дать протокол к моей структуре декларации, не удался, что и следовало ожидать, так как я не оказываю никакой реализации свойств:
struct Anime : MediaType {
/// MARK: - MediaType
}
/// Compares two Anime_ objects. Two Anime_ objects are considered equal when they have the same ID and title.
func ==(lhs: Anime, rhs: Anime) -> Bool {
return (lhs.ID == rhs.ID) && (lhs.title == rhs.title)
}
Это терпит неудачу с:
Тип «Аним» не соответствует протоколу
Моей следующей попытке «MEDIATYPE» был написать расширение для MediaType, и бросить свойства там:
extension MediaType {
/// The ID of the media, as assigned by MyAnimeList.
let ID: Int
/// The title of the media.
let title: String
/// Other titles by which this anime may be commonly known (only available in details requests).
let otherTitles: (synonyms: [String], english: [String], japanese: [String])?
/// The global ranking of the title (only available in anime details requests).
let rank: Int?
/// Rank of the title based on popularity (number of people adding title to the list) (only available in details requests).
let popularityRank: Int?
/// URL to a representative image of the title. Usually a "cover" image.
let imageURL: String
/// A list of adaptations of this media, or other media on which this media is based (only available in details requests).
let adaptations: Relationships
/// The user's rating of the media.
let memberScore: Float
/// Number of MyAnimeList members that that added the title to their list (only available in details requests).
let membersCount: Int?
/// The number of MyAnimeList members that have this title on their favorites list (only available in details requests).
let favoritedCount: Int?
/// A short HTML-formatted description of the media.
let synopsis: String
/// A list of genres for this title (only available in details requests).
let genres: [String]?
/// Popular tags for the title as assigned by MyAnimeList members (only available in details requests).
let tags: [String]
}
Это не сработало:
Расширения не могут содержать сохраненные свойства.
И у него был единственный недостаток, который мне действительно не понравился: я уже дублировал код, копируя свойства протокола в расширение.
Так что, в конце концов, я никогда не смог бы получить мои свойства для «распространения» объектов, соответствующих протоколу, поэтому в итоге я добавил свойства в структуру Anime
.
struct Anime : MediaType {
/// MARK: - MediaType
/// The ID of the media, as assigned by MyAnimeList.
let ID: Int
/// The title of the media.
let title: String
/// Other titles by which this anime may be commonly known (only available in details requests).
let otherTitles: (synonyms: [String], english: [String], japanese: [String])?
/// The global ranking of the title (only available in anime details requests).
let rank: Int?
/// Rank of the title based on popularity (number of people adding title to the list) (only available in details requests).
let popularityRank: Int?
/// URL to a representative image of the title. Usually a "cover" image.
let imageURL: String
/// A list of adaptations of this media, or other media on which this media is based (only available in details requests).
let adaptations: Relationships
/// The user's rating of the media.
let memberScore: Float
/// Number of MyAnimeList members that that added the title to their list (only available in details requests).
let membersCount: Int?
/// The number of MyAnimeList members that have this title on their favorites list (only available in details requests).
let favoritedCount: Int?
/// A short HTML-formatted description of the media.
let synopsis: String
/// A list of genres for this title (only available in details requests).
let genres: [String]?
/// Popular tags for the title as assigned by MyAnimeList members (only available in details requests).
let tags: [String]
/// MARK: - Anime
}
И это, казалось, сработало. Но теперь у меня есть мои свойства как в MediaType
, так и в Anime
. В ООП вы избегаете дублирования кода путем подкласса.
Итак, я повторяю свой вопрос здесь: Я неправильно понимаю Программирование, ориентированное на протокол, или является недостатком POP, который вы должны копировать и вставлять логику, специфичную для протокола, всякий раз, когда вы выполняете структуру/класс/перечисление ?
Вы можете использовать * вычисленные * свойства в расширении протокола, но расширения не могут иметь регулярные свойства. Это ограничение останется. –
Это определенно выглядит так, что в соответствии с этим ограничением не будет реализована реализация свойств по умолчанию в протоколах. Интересно подумать об этом. –
Согласен. Я надеюсь, что расширения позволят хранить в будущем. –