ソフトウェアを作成するときは、幅広い設計原則を理解すると便利です。 最も適切な原理でシステムを設計する方法を理解することは、開発と頭痛の数え切れないほどの時間を節約することができます。

まず、継承について少し話しましょう。 継承は、クラスが親クラスから状態や動作を継承するときです。 私たちはゲームを設計しているとしましょう、と私は犬が必要です:

class Dog {
func bark(){
print("Bark")
}
}

しばらくすると、私たちのソフトウェアはすべてのものと同様にCatsを必要とすることに気付き、Catクラスを作成します:

class Cat{
func .meow(){
print("Meow!")
}
}

自然が呼んでいるので、追加します。CatおよびDogクラスへのpoop():

class Dog {
func bark(){
print("Bark")
}
func poop(){
print("Poop")
}
}class cat{
func meow(){
print("Meow")
}
func poop(){
print("Poop")
}
}

この例では、私たちはそれらがうんちすることができます二つの動物を持っています。 残念ながら、両方ともpoop()の実装を提供しているため、ここにはいくつかのコードの重複があります。 だから私たちは持ち上げます。poop()を共有動物クラスにします。

Animal
.poop()Dog
.bark()Cat
.meow()

今、私たちはどこでもうんち動物の多くを持っているので、私たちはcleaningrobotを必要としています:

CleaningRobot
.drive()
.clean()

また、できるMurderRobotが必要です。ドライブ()と.kill()ある猫と犬。白い床の上にうんこ()ing:

MurderRobot
.drive()
.kill()

以来。drive()がCleaningRobotとMurderRobotの間で複製されるようになりました。

Robot
.drive()CleaningRobot
.clean()MurderRobot
.kill()

これは全体の構造がどのように見えるかです:

Robot
.drive()CleaningRobot
.clean()MurderRobot
.kill()Animal
.poop()Dog
.bark()Cat
.meow()

“私たちの顧客はMurderRobotDogを要求します。 それはできる必要があります。キル(),.ドライブ(),.bark()が、poop()はできません。

そして今、私たちはねじ込まれています。 私たちは単にMurderRobotDogをこの継承階層にうまく適合させることはできません。 新しい親オブジェクトを作成し、共有されているすべての機能を配置することができます:

GameObject
.bark()Robot
.drive()CleaningRobot
.clean()MurderRobot
.kill()MurderRobotDogAnimal
.poop()DogCat
.meow()

しかし、それはあなたのオブジェクトが彼らが使用しない機能のトンを持っていることを意味するので、あなたはゴリラ/バナナの問題に終わ

しかし、Swiftのプロトコルでこれをモデル化することはできます。プロトコルはどのようにしてより良い抽象化を提供できますか?

Swiftのプロトコルは、クラスが採用できるメソッドまたはプロパティを定義します。 ここに例があります:

protocol Barker {
func bark()
}
protocol Pooper {
func poop()
}
protocol Driver {
func drive()
}
protocol Cleaner {
func clean()
}
protocol Killer {
func kill()
}

クラスは複数のプロトコルを採用することができますので。 MurderRobotDogクラスはBarker, Killer and driverプロトコルを採用し、MurderRobotDogクラスがbark(), kill(), and clean()の実装を提供することを意味します。

class MurderRobotDog: Barker,Killer, Driver{
func bark() {
print("Bark!")
}
func driver() {
print("Drive!")
}
func killer() {
print("Kill!")
}}

Swift2.0では、プロトコル拡張を使用したデフォルトの実装を提供することで、コードの重複を削除できるようになりました:

protocol Barker {
func bark()
}
extension Barker {
func bark() {
print("Bark!")
}
}class Dog: Barker{}
let myDog = Dog()
myDog.bark() // prints "Bark!"

そこで、壊れた継承ツリーの例を見て、プロトコル(インターフェイス)を使用してそれを再構築する方法を見てきました。

おそらく今あなたの心にある質問は、それぞれをいつ使用するかです。 まあ…大多数の開発者は、継承よりもインターフェイスを優先すべきであることに同意します。 多くの人が、何かが”is a”関係を持っている場合は、継承を使用する必要があると言います。 たとえば、Mattiasは”人間”であるため、私は人間を継承することができます。 関係が「持っている」という性質のものである場合、車は「持っている」エンジンのように、コンポジションを使用する必要があります。

結論

システムを設計するときは、モデルに適した設計原理を選択することが重要です。 多くの状況では、最初にinterfaceを使用する方が良いでしょう。 それはより柔軟で強力で、そしてそれはまた非常に簡単です。

コメントを残す

メールアドレスが公開されることはありません。