私は Swift のプロトコル指向プログラミングの概念に本当に魅了されています。そのため、昨年作成した古いプロジェクト (元々は OOP フレームワークでした) を POP に移行しています。
この段階で私が抱えている問題は、私が POP を正しく理解していないか、真にプロトコル指向のフレームワークを作成するためのすべてが Swift 2.0 ベータ版にないためである可能性があります。 POP の特定の側面)。
プロトコル指向プログラミングは、世界に導入されてから 1 か月も経っていないまったく新しいプログラミング パラダイムであるため、それについて書かれたコンテンツはあまりありません (このトピックに関して私が見つけた唯一のチュートリアルは、私が抱えている問題に対処していません。 WWDC ビデオもそうではありませんでした)。
とにかく、要点: 私はここで何か間違ったことをしている、またはプロトコル指向プログラミングの欠点の 1 つは、多くのコードを繰り返さなければならないことです。適例:
多くのプロパティがあり、プロトコルにも準拠している次のプロトコルがあり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
で、他の 2 つのクラスはそこから継承されていました。そのため、彼らはこれらすべてのプロパティを無料で取得しました。
しかし、そのプロトコルに準拠するオブジェクトに、それらのプロパティのデフォルトの実装 (つまり、ゲッター) を与えることができないように見えますか?
私が最初に試みたのは、単にプロトコルを構造体宣言に与えることでしたが、失敗しました。これは、プロパティの実装を提供していなかったため、予想されていました。
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)
}
これは次の場合に失敗します。
タイプ「Anime」はプロトコル「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]
}
これはうまくいきませんでした:
拡張機能には、保存されたプロパティが含まれていない場合があります。
そして、私が本当に気に入らなかった欠点が 1 つあります。それは、プロトコルのプロパティを拡張機能にコピーすることによって、既にコードを複製していたことです。
そのため、結局、プロトコルに準拠するオブジェクトにプロパティを「分散」させることができなかったため、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
ます。OOP では、サブクラス化によってコードの重複を回避します。
だから私はここで私の質問を繰り返します:私はプロトコル指向プログラミングを誤解していますか、それとも構造体/クラス/列挙型を準拠させるたびにプロトコル固有のロジックをコピーして貼り付ける必要があるというPOPの欠点ですか?