소프트웨어를 만들 때 광범위한 설계 원칙을 이해하는 것이 유용합니다. 가장 적절한 원칙으로 시스템을 설계하는 방법을 이해하면 수많은 개발 시간과 두통을 줄일 수 있습니다.

먼저 상속에 대해 조금 이야기 해 봅시다. 상속은 클래스가 부모 클래스에서 상태 및/또는 동작을 상속하는 경우입니다. 우리가 게임을 디자인한다고 가정해 봅시다.그리고 저는 개가 필요합니다.:

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

잠시 후,우리는 모든 것과 마찬가지로 우리의 소프트웨어가 고양이를 필요로한다는 것을 깨닫기 때문에 고양이 클래스를 만듭니다:

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

자연이 호출하기 때문에 추가합니다.고양이와 개 클래스에 똥():

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

이 예에서 우리는 똥을 낼 수있는 두 마리의 동물을 가지고 있습니다. 불행히도 둘 다poop()에 대한 구현을 제공하므로 여기에 코드 중복이 있습니다. 그래서 우리는 들어 올립니다.똥()공유 동물 클래스에.

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

이제 우리는 많은 동물들이 도처에 똥을 피우고 있으므로 청소 로봇이 필요합니다:

CleaningRobot
.drive()
.clean()

당신은 또한 할 수있는 살인 로봇이 필요합니다.드라이브()과.킬()있는 고양이와 개.똥()모든 흰색 바닥을 보내고:

MurderRobot
.drive()
.kill()

이후.드라이브()는 이제 청소 로봇과 살인 로봇 사이에 복제됩니다.우리는 그것을 넣을 로봇 클래스를 만듭니다.

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

이것은 전체 구조의 모습입니다:

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

“우리의 고객은 살인을 요구합니다.로봇 개. 그것은 할 수 있어야합니다.킬(),.드라이브(),.나무 껍질(),하지만 똥 수 없습니다().

그리고 지금,우리는 망했다. 우리는 단순히 살인 로봇 독을이 상속 계층 구조에 잘 맞출 수 없습니다. 리는 당신 공되는 모든 기능 넣 새로 부모 개체를 만들 수 습니다:

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

하지만 그 개체는 사용하지 않는 기능의 톤이있을 것이라는 점을 의미한다,그래서 당신은 고릴라/바나나 문제로 끝—당신은 바나나를 요청하지만,당신은 고릴라가 바나나와 그것으로 전체 정글을 들고 결국.

그러나 우리는 이것을 스위프트의 프로토콜로 모델링 할 수 있습니다.프로토콜이 어떻게 더 나은 추상화를 제공 할 수 있습니까?

스위프트의 프로토콜은 클래스가 채택 할 수있는 메소드 또는 속성을 정의합니다. 다음은 예입니다:

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

클래스는 여러 프로토콜을 채택 할 수 있기 때문입니다. 살인 로봇 독 클래스는Barker, Killer and driver프로토콜을 채택하여 살인 로봇 독 클래스는bark(), kill(), and clean()에 대한 구현을 제공합니다.

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

스위프트 2.0 현재,우리는 이제 프로토콜 확장을 사용하여 기본 구현을 제공하여 코드 중복을 제거 할 수 있습니다:

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

그래서 우리는 고장난 상속 트리의 예를 살펴본 다음 프로토콜(인터페이스)을 사용하여 재구성하는 방법을 살펴 보았습니다.

지금 당신의 마음에 아마 질문은-각 하나를 사용하는 경우— 음…개발자의 대부분은 우리가 상속을 통해 인터페이스를 선호해야한다는 데 동의합니다. 많은 사람들이 무언가가”이다”관계가있는 경우,당신은 상속을 사용해야한다고 말할 것입니다. 예를 들어,마티 아스는”사람”이므로 나는 사람을 물려받을 수 있습니다. 관계는 자동차”가”엔진과 같은 성격”이”의 경우,당신은 구성을 사용해야합니다.

결론

시스템을 설계할 때는 모델에 적합한 설계 원리를 선택하는 것이 중요합니다. 많은 경우에,그것은 처음에 인터페이스를 사용하는 것이 좋습니다. 그것은 더 유연하고 강력하며 또한 매우 쉽게 할 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다.