Edited at

【Swift】クラスの継承とプロトコルの準拠の使い分け


抽象概念の共有

各クラスや構造体に共通の抽象概念を共有する場合、クラスでは親のクラスを継承しその親の特徴を子にも共有できるようにし、プロトコルではその決まりごとを準拠して共通のルール(特徴)を他の構造体などと統一することができます。

親の特徴を受け継ぎ、子でも使えるようにするこの機能は一見同じように見えますが、実際はどのような違いがあり、どのように状況に合わせて使っていけば良いのでしょうか???

今回はこれについて考えていきます。


プロトコルの準拠

Swiftの機能であるプロトコルを準拠した場合の利点について解説していきます。

まず最初にクラスで実装した際の欠点について考えていきます。

以下のコードを見て、どのあたりが問題でしょうか?

問題点は2点あります。

一つ目は、インスタンス化してはいけない親クラスのFoodがインスタンス化可能であること。

二つ目は、店ではなく自然に生えているberryクラスにもshop変数が継承されているということです。

それでは上記の2点を解決していくためにプロトコルを用いていきます。

class Food {

var shop: String?
func taste()
func eat()
}

class Sushi : Food {
override func eat() {
print("dip a soy source")
}
}

class Berry : Food {
override func eat() {
print("take from tree")
}
}

以下のコードがプロトコルで実装したコードです。

親をプロトコルにしたため、誤ってインスタンス化される恐れがなくなりました。そして変数shopがSushiだけに準拠でき、必要のない要素を各構造体に入れずにすみました。また、Foodプロトコルを拡張しtasteメソッドを実装することで構造体に共通のメソッドの記述しなくてすみました。

protocol Shop {

var shop: String { get set}
}

protocol Food {
func taste()
func eat()
}

extension Food {
func taste() {print("tasty!")}
}

struct Sushi : Food, Shop {
var shop: String
func eat() {print("dip a soysource")}
}

struct Berry : Food {
func eat() {print("take from tree")}
}


クラスの継承

クラスの継承を用いる時は複数の型同士で同一のストアドプロパティを共有したいときに利用します。

以下のコードのように継承するクラス達が同じ持ち主(ストアドプロパティ)である場合、クラスのような参照型を利用すると、同じストアドプロパティを参照するのでこのような結果になります。

このように同じ値を共有したい場合はクラスの継承を使用するべきです。一応プロトコルでも実装可能ではありますが、複雑で冗長なコードになるので使わないのが得策です。

class Item {

var owner: String? {
didSet {
guard let owner = owner else {return}
print("\(owner) has a this item."
}
}
}

class Phone : Item {}

class Shoes : Item{}

let phone = phone
phone.owner = "Sanetugu Nekoyasiki"

//実行結果
Sanetugu Nekoyasiki has a this item.