OOP

hyun·2025년 6월 10일
0

iOS

목록 보기
13/54

객체지향 프로그래밍의 특징,
실제로 구현하거나 경험한 적 있는 것을 예시와 함께 설명


 OOP의 특징

캡슐화 / 상속 / 다형성 / 추상화

캡슐화

속성, 메서드를 하나의 객체 안에 묶어서 직접 접근을 제한하고
인터페이스를 통해서 조작할 수 있게 함

상속

기존 클래스로 새로운 클래스를 만들고 부모 클래스의 속성, 기능을 물려받아서 재사용이나 확장이 가능하게 하는 것

다형성

같은 인터페이스를 통해서 서로 다른 타입의 객체를 다룰 수 있는 것
메서드 오버라이딩 등을 통해 구현

추상화

복잡한 내부 구현을 숨기고 필요한 기능만 외부에 노출함

 실제 경험

상속

Car 클래스가 기본 클래스 역할을 하고

ElectricCar, HybridCar 등이 Car를 상속받아 기능을 확장하거나 변경

class ElectricCar: Car {
    // 전기차 기능 구현
}

class HybridCar: Car {
    // 하이브리드 기능 구현
}

다형성

Car 타입의 변수에 ElectricCar나 HybridCar 인스턴스를 할당해서 사용

drive()와 stop() 같은 메서드가 open으로 선언돼서 하위 클래스에서 오버라이딩 가능

같은 메시지(drive())를 호출해도 실행되는 메서드는 실제 인스턴스 타입에 따라 다르게 동작함

let car: Car = ElectricCar(brand: "테슬라", model: "Model 3", year: "2025")
car.drive() // ElectricCar에서 오버라이딩된 drive() 실행 가능

3. 추상화

Car 클래스가 자동차라는 개념을 추상화해서
브랜드, 모델, 연도, 엔진이라는 공통 속성과 기능(drive(), stop())을 정의

engine은 Engine 프로토콜 타입으로 선언돼서
구체적인 엔진 구현을 추상화하여 다룰 수 있음

open var engine
: Engine 으로 어떤 Engine 프로토콜을 채택한 타입이든 할당 가능하니까
엔진 교체 메서드도 가능하게 설계

public init(brand: String, model: String, year: String, engine: any Engine) {
    ...
    self.engine = engine // Engine 프로토콜 타입으로 추상화
}

protocol에 대해서 설명,
protocol을 활용해서 의존성을 줄인 경험,
protocol을 class 대신 사용하는 것이 왜 도움이 될 수 있는지 설명


 Protocol이란??

Swift에서 규칙이나 청사진 역할을 하는 것? 타입??

특정 메서드, 프로퍼티, 이니셜라이저로 구현하도록 강제하는 인터페이스

클래스, 구조체, 열거형이 프로토콜을 채택하면 규칙에 맞게 기능을 구현해야 함

protocol Drivable {
    func drive()
    func stop()
}

Protocol로 의존성을 줄인 경험 예시

어떤 클래스가 다른 클래스를 직접 생성해서 의존하면 결합도가 높아져서
유지보수나 테스트가 어려워짐

class Engine {
    func start() { print("start") }
}

class Car {
    let engine = Engine()  // Car가 Engine에 강하게 의존함

    func drive() {
        engine.start()
        print("drive")
    }
}

이 경우 Car는 항상 Engine이라는 구체 클래스에 의존해서 바꿔 쓰기 어려운데

프로토콜로 의존성 낮추기

protocol EngineProtocol {
    func start()
}

class Engine: EngineProtocol {
    func start() { print("Engine starts") }
}

class ElectricEngine: EngineProtocol {
    func start() { print("Electric engine starts quietly") }
}

class Car {
    let engine: EngineProtocol  // 프로토콜 타입에 의존

    init(engine: EngineProtocol) {
        self.engine = engine
    }

    func drive() {
        engine.start()
        print("Car drives")
    }
}

let combustionEngine = Engine()
let electricEngine = ElectricEngine()

let car1 = Car(engine: combustionEngine)
let car2 = Car(engine: electricEngine)

Car는 EngineProtocol에만 의존하니까 어떤 구체 엔진인지 몰라도 되고
쉽게 변경할 수 있음

이렇게 하면 테스트 할 때 Mock 엔진 주입도 가능해지고 확장성도 좋아짐

3. 클래스 대신 프로토콜을 사용하는 이유

직접 의존하면 구현에 너무 묶임 → 유지보수 및 확장 어려움

프로토콜은 구현과 분리된 추상화된 계약이기 때문에 의존성을 느슨하게 만들어 줌

프로토콜은 여러 프로토콜 채택이 가능하지만 클래스는 단일 상속만 가능

클래스가 아닌 타입도 프로토콜을 채택할 수 있어서 더 유연

테스트용 Mock 객체를 만들어 주입하기 편함

0개의 댓글