[Swift] 상속

개자이너·2022년 2월 3일
0

내맘대로 Swift

목록 보기
5/6

Swift에 대해서 개인적으로 공부하고 기록한 포스팅입니다.

구조체를 활용한 상속?

중복된 속성이 존재할 때,

  • 객체 지향 설계에서는 중복된 속성을 부모 클래스를 통해 캡슐화가 가능합니다.
  • 스위프트에서 상속을 사용하기 위해서는 구조체가 아닌 클래스를 이용해야 합니다. (Call by Ref)

아래와 같이 상속을 위해서는 구조체를 활용할 수 없습니다.

struct User {
	let email: String
    let password: String
    let joinDate: Date
    
    var level: Int
    var exp: Int
}

struct Admin {
	let email: String
    let password: String
    let joinDate: Date
    
    var logs: [String]
}

클래스를 활용한 상속

클래스의 특징

  • 구조체와 다르게 멤버 초기화 메서드가 자동으로 제공되지 않습니다.
  • 사용자는 프로퍼티의 초기값을 지정하거나, 초기화 메서드를 통해 초기화를 수행 해주어야 합니다.
class Account {
	let email: String
    let password: String
    let joinDate: Date
    
    init(email: String, password: String, joinDate: Date) {
		self.email = email
	    self.password = password
	    self.joinDate = joinDate
	}
}

위 클래스를 상속받은 User Class를 만들고자 할 때는 아래와 같이 상속합니다.

[중요]
초기화 메서드를 작성할 때는 자신의 속성을 먼저 초기화하고, 부모의 지정 초기화 메서드를 통해 초기화를 진행해야 합니다.

class User: Account {
	var level: Int
    var exp: Int
    
    init(email: String, password: String, joinDate: Date, level: Int, exp: Int) {
    	self.level = level
        self.exp = exp
        
        // 자신의 속성을 먼저 초기화 하고, 부모 지정 초기화 메서드를 통해서 초기화를 진행합니다.
        super.init(email: email, password: password: joinDate: joinDate)
    }
}

함수 오버로딩 (다형성)

class Account {
	{ ... 중략 ... }
    
	func display() {
    	print("Account Display")
    }
}

class User: Account {
	{ ... 중략 ... }
    
	override func display() {
    	print("Account Display")
    }
}

class Admin: Account {
	{ ... 중략 ... }
    
	override func display() {
    	print("Admin Display")
    }
}

let arr: [Account] = [
	User(...),
    Admin(...),
]

for e in arr {
	e.display()
}

// 출력 : "Account Display"
// 출력 : "Admin Display"

클래스를 활용한 상속의 문제점

경직된 설계

새로운 Account 기반 타입을 도입할 때, 기존에 설계한 구조와 다를 경우 전체적인 구조를 변경해야 하는 어려움이 있습니다.

만약 Account 가 가져야 하는 값들이 Guest 대응을 위해서 email, psssword가 필요 없는 경우는 어떻게 해야할까요?

Account 에 대한 설계를 모두 뜯어 고치는 상황이 생길 것입니다.

클래스 사용

상속을 이용하기 위해서는 참조 타입인 Class를 사용해야 합니다.

Struct를 활용할 수 있다면 Class보다 활용하는 것이 더욱 효율적일 수도 있습니다. Class는 Reference Type으로 메모리 관리를 해주어야 하기 때문입니다.

Enum을 사용해 Class를 활용한 상속에 대한 문제점을 어느정도 해결할 수 있다.

Enum을 활용한 상속

장점

  1. 새로운 유형을 추가할 때, 기존 코드 구조적인 변경이 필요하지 않습니다.
  2. 구조체를 활용할 수 있습니다.

단점

  1. Enum을 사용하면 중복된 항목을 별도로 캡슐화하는 것이 어렵습니다.
  2. 다형성을 구현하기 위해서는 직접 분기 코드를 작성해야 합니다.

표현 방법

struct User {
	let email: String
    let password: String
    let joinDate: String
    
    var level: Int
    var exp: Int
}

struct Admin {
	let email: String
    let password: String
    let joinDate: Date
    
    var logs: [String]
}

enum Account {
	case user(User)
    case admin(Admin)
}

let arr: [Account] = [
	.user(User(email: "a@abc.com", password: "123", joinDate: Date(), level: 1, exp: 0)),
    .admin(Admin(email: "aa@abc.com", password: "123", joinDate: Date(), logs: []))
]

함수 오버로딩 (다형성)

Enum으로 상속의 관계를 흉내냈을 경우에 Class를 활용한 상속의 다형성으로 함수 오버로딩을 하고자 할 때는 어떻게 할 수 있을까?

Switch-case를 활용하면 됩니다.

enum Account {
	case user(User)
    case admin(Admin)
    
    func display() {
    	switch self {
        case let .user(user):
          print("User Display - \(user)")
            
        case let .admin(admin):
          print("Admin Display - \(admin)")
        }
    }
}

let arr: [Account] = [
	.user(User(email: "a@abc.com", password: "123", joinDate: Date(), level: 1, exp: 0)),
    .admin(Admin(email: "aa@abc.com", password: "123", joinDate: Date(), logs: []))
]

for e in arr {
	e.display()
}
profile
개발과 디자인을 다 하려는 욕심 그득한 노예

0개의 댓글