Search

Object-Oriented Programming(OOP)

Swift는 Apple에서 개발한 현대적이고 강력한 프로그래밍 언어로, 객체지향프로그래밍 패러다임을 완벽하게 지원합니다.

객체지향프로그래밍(Object-Oriented Programming)

객체지향프로그래밍은 프로그램을 독립된 단위인 객체(Object)들로 나누고 이 객체들의 상호작용을 통해 프로그램을 설계하고 구현하는 패러다임입니다. 각 객체는 속성과 메서드를 가지며 클래스라는 틀을 사용하여 객체를 생성합니다.

객체지향프로그래밍의 장점

모듈성과 재사용성 - 객체는 독립적이고 재사용 가능한 단위로 구성되므로 코드를 모듈화 하고 재사용하기 용이합니다. 이로써 코드의 유지보수가 편리해지며 생산성을 높일 수 있습니다.
유지보수 용이성 - 코드의 변경이나 구현에 대한 영향을 최소화할 수 있습니다.

객체지향프로그래밍의 단점

복잡성 - 객체지향프로그래밍은 강력한 도구지만 복잡한 클래스 계층 구조나 다양한 객체 간의 관계를 다루는 것은 어려울 수 있습니다. 잘못된 설계나 사용 시 의도하지 않은 문제가 발생할 수 있습니다.
용량 - 객체지향프로그래밍은 클래스와 객체를 사용하므로 코드의 구조가 복잡해질 수 있습니다. 클래스 정의, 객체 생성 및 관리를 위한 코드 등이 추가되므로 컴파일된 바이너리 파일의 크기가 증가할 수 있습니다. 더 많은 메모리 공간이 필요하게 되며 이는 앱의 다운로드 크기나 메모리 사용량 측면에서 고려해야 할 요소가 될 수 있습니다.
실행속도 - 객체지향프로그래밍은 객체 간의 상호작용과 메서드 호출 등의 오버헤드를 동반합니다. 이로 인해 프로그램의 실행 속도가 조금 느릴 수 있습니다. 예를 들어, 객체의 생성과 소멸, 메서드 호출 등은 함수 호출보다 약간의 추가 작업이 필요하므로 작은 규모의 작업에서는 큰 문제가 되지 않을 수 있으나 대규모의 반복적인 작업에서는 성능 저하를 불러올 수 있습니다.

객체지향프로그래밍 특징

객체지향프로그래밍은 캡슐화상속추상화다형성이라는 4가지 특징을 가집니다.

1. 캡슐화(Encapsulation)

캡슐화는 변수와 함수를 하나의 단위로 묶는 것을 뜻합니다. 이렇게 하면 데이터에 직접 접근하는 것을 제어하고 데이터의 변경이나 조작이 오로지 해당 객체의 메서드를 통해서만 이루어지도록 합니다. 이로써 외부에서의 무작위 접근을 방지하고 안정성을 높일 수 있습니다.

1-1. 캡슐화의 특징

데이터 은닉 - 내부 데이터에 직접 접근하지 못하도록 함으로써 데이터의 무결성을 보장하고 부작용을 최소화합니다.
인터페이스 제공 - 외부에는 객체의 공개된 메서드를 통해서만 접근할 수 있으며, 이는 사용자에게 안정적이고 편리한 인터페이스를 제공합니다.
유지보수 - 내부 구현을 변경해도 외부 코드에 영향을 주지 않도록 해 코드 유지보수를 용이하게 합니다.

1-2. 캡슐화 예시 코드

class BankAccount { private var balance: Double = 0.0 func deposit(amount: Double) { if amount > 0 { balance += amount print("Deposited $\(amount) New balance: $\(balance)") } else { print("Invalid deposit amount.") } } func withdraw(amount: Double) { if amount > 0 && amount <= balance { balance -= amount print("Withdraw $\(amount) New balance: $\(balance)") } else { print("Invalid withdrawal amount or insufficient funds.") } } func getBalance() -> Double { return balance } } let account = BankAccount() account.deposit(amount: 1000.0) // "Deposited $1000.0 New balance: $1000.0" account.withdraw(amount: 500.0) // "Withdraw $500.0 New balance: $500.0" // account.balance // Error: 'balance' is inaccessible due to 'private' protection level // 캡슐화를 통한 인터페이스 사용 let currentBalance = account.getBalance() print("Current balance: $\(currentBalance)") // "Current balance: $500.0"
Swift
복사
위 코드에서 'BankAccount' 클래스는 'balance'라는 private 속성을 가지고 있습니다. 이로써 외부에서 직접적으로 'balance'에 접근할 수 없으며 'deposit'와 'withdraw' 메서드를 통해서만 입출금이 이루어집니다. 이렇게 함으로써 데이터의 무결성을 보장하고 사용자는 안전한 방식으로 은행 계좌를 사용할 수 있습니다.

2. 상속(Inheritance)

상속은 이미 존재하는 클래스의 속성과 메서드를 물려받아 새로운 클래스를 정의합니다. 자식 클래스는 부모 클래스의 기능을 확장하거나 변경하여 사용할 수 있습니다.

2-1. 상속의 특징

재사용성 - 기존 클래스의 코드를 재사용하여 새로운 클래스를 작성할 수 있어 코드 중복을 줄일 수 있습니다. -> 유지보수에 용이
확장성 - 자식 클래스는 부모 클래스의 기능을 확장하거나 추가적인 기능을 정의할 수 있습니다.
계층 구조 - 클래스들 사이에 계층 구조가 형성되어 코드의 구조를 보다 명확하게 나타낼 수 있습니다.
다형성 - 부모 클래스 타입으로 자식 클래스의 객체를 다룰 수 있으므로 코드의 유연성을 증가합니다.

2-2. 상속 예시 코드

class Vehicle { var brand: String init(brand: String) { self.brand = brand } func drive() { fatalError("Subclasses must override this method") } } class Car: Vehicle { var model: String init(brand: String, model: String) { self.model = model super.init(brand: brand) } override func drive() { print("\(brand) \(model) is driving") } } class Bicycle: Vehicle { override func drive() { print("Bicycle is pedaling") } } let myCar = Car(brand: "Hyundai", model: "Avante") myCar.drive() // "Hyundai Avante is driving"let myBicycle = Bicycle(brand: "Giant") myBicycle.drive() // "Bicycle is pedaling"
Swift
복사
위 코드에서 'Vehicle' 클래스는 모든 차량의 공통 속성인 'brand'를 가지고 있습니다. 이 클래스를 상속하여 'Car' 클래스와 'Bicycle' 클래스를 생성합니다. 'Car' 클래스는 'Vehicle' 클래스의 속성을 물려받고 'drive' 메서드를 재정의하여 자동차 운전을 표현합니다. 마찬가지로 'Bicycle' 클래스는 'Vehicle' 클래스의 'drive' 메서드를 재정의하여 자전거 타기를 표현합니다.

3. 추상화(Abstraction)

추상화는 객체들의 공통된 특징을 도출하여 이를 기반으로 클래스를 정의합니다.

3-1. 추상화의 특징

복잡성 감소 - 추상화를 통해 핵심 개념과 기능에 집중함으로써 복잡성을 감소시킬 수 있습니다.
유지보수 - 추상화된 코드는 변경이 발생할 때 해당 추상화 계층만 수정하면 되므로 유지보수가 용이합니다.
재사용성 - 추상화된 클래스를 기반으로 다양한 객체들을 생성하고 재사용할 수 있습니다.

3-2. 추상화 예시 코드

protocol Shape { func area() -> Double func description() -> String } class Circle: Shape { let radius: Double init(radius: Double) { self.radius = radius } func area() -> Double { return Double.pi * radius * radius } func description() -> String { return "Circle with radius \(radius)" } } class Rectangle: Shape { let width: Double let height: Double init(width: Double, height: Double) { self.width = width self.height = height } func area() -> Double { return width * height } func description() -> String { return "Rectangle with width \(width) and height \(height)" } } let circle = Circle(radius: 5.0) let rectangle = Rectangle(width: 4.0, height: 3.0) print(circle.description()) // "Circle with radius 5.0" print("Area: \(circle.area())") // "Area: 78.53981633974483" print(rectangle.description()) // "Rectangle with width 4.0 and height 3.0" print("Area: \(rectangle.area())") // "Area: 12.0"
Swift
복사
위 코드에서 'Shape' 프로토콜은 추상화 계층을 나타내며 'Circle'과 'Rectangle' 클래스는 'Shape' 프로토콜을 구현하여 추상화된 개념을 구체화하고 있습니다. 이를 통해 도형 객체들의 공통된 특성과 동작을 추상화하여 표현하고 객체들 간의 관계와 기능을 쉽게 이해하고 확장할 수 있습니다.

4. 다형성(polymorphism)

다형성은 다양한 클래스들이 동일한 인터페이스(이름, 매개변수, 반환값의 형식)를 통해 다양한 방식으로 동작할 수 있는 능력을 의미합니다. 다시 말해서, 다형성은 같은 메서드나 인터페이스를 가진 객체들이 실제로는 다른 동작을 수행할 수 있도록 하는 개념입니다.
예를 들어, 다양한 동물들이 '소리를 내는' 동작을 할 때 각각 다른 소리를 내는 것을 생각해 볼 수 있습니다. 각 동물은 '소리를 내는'이라는 특성을 공유하지만, 실제로는 그 특성을 다양한 방식으로 구현하고 있습니다.

4-1. 다형성의 특징

재사용성 - 같은 인터페이스를 구현할 다양한 클래스들을 사용하여 유사한 작업을 수행하는 코드를 재사용할 수 있습니다.
유연성과 확장성 - 새로운 클래스를 추가하거나 기존 클래스를 수정하지 않고도 코드를 확장하거나 변경할 수 있습니다.
유지보수 - 다형성을 이용하면 변경 사항을 최소화하면서도 기능을 수정하거나 추가할 수 있습니다.

4-2. 다형성 예시 코드

class Animal { func makeSound() { fatalError("Subclasses must override makeSound()") } } class Dog: Animal { override func makeSound() { print("Woof") } } class Cat: Animal { override func makeSound() { print("Meow") } } class Bird: Animal { override func makeSound() { print("Chirp") } } func performAnimalSound(_ animal: Animal) { animal.makeSound() } let dog = Dog() let cat = Cat() let bird = Bird() performAnimalSound(dog) // "Woof" performAnimalSound(cat) // "Meow" performAnimalSound(bird) // "Chirp"
Swift
복사
위 코드에서 'Animal' 클래스는 추상 클래스로서 'makeSound()' 메서드를 정의합니다. 이 메서드는 서브클래스들이 오버라이드해야 하는 메서드입니다. 'Dog', 'Cat', 'Bird' 클래스는 각각 'Animal' 클래스를 상속받아 'makeSound()' 메서드를 오버라이드하여 구현합니다.
'performAnimalSound(_:)' 함수는 다형성을 활용하여 인자로 전달된 'Animal' 객체의 'makeSound()' 메서드를 호출합니다. 이로써 서로 다른 서브클래스의 객체에 대해 동일한 메서드를 호출하면서도 각 객체의 구체적인 동작을 실행할 수 있습니다.