Object Oriented Programming
객체지향 프로그래밍이란 무엇인가요? 그리고 객체지향의 4대 특징에 대해 설명해주세요.
객체지향 프로그래밍(OOP)은 현실 세계의 개념을 소프트웨어 객체로 모델링하여, 데이터와 동작을 하나의 단위로 묶는 프로그래밍 패러다임입니다. 4대 특징은 다음과 같습니다:
캡슐화(Encapsulation): 데이터와 그 데이터를 조작하는 메서드를 하나의 객체로 묶고, 외부에는 필요한 부분만 노출합니다.
상속(Inheritance): 기존 클래스를 재사용하여 새로운 클래스를 정의함으로써 코드의 중복을 줄이고, 계층적 관계를 형성합니다.
추상화(Abstraction): 공통된 속성과 기능을 추출하여 모델링하고, 복잡성을 줄입니다.
다형성(Polymorphism): 같은 인터페이스를 통해 서로 다른 구현을 사용할 수 있어, 유연한 설계를 가능하게 합니다.
캡슐화와 정보은닉은 같은 개념인가요? 차이점이 있다면?
캡슐화는 객체의 상태(필드)와 동작(메서드)을 하나로 묶는 개념입니다. 정보은닉은 캡슐화의 목적 중 하나로, 외부에 내부 구현을 숨기고 필요한 인터페이스만 제공하는 것을 말합니다. 즉, 캡슐화는 구조적 개념이고, 정보은닉은 그에 따른 효과 또는 전략입니다.
데이터를 직접 접근하지 못하게 막았을 때, 조회/수정은 어떻게? 장단점은?
보통 getter
와 setter
메서드를 통해 간접적으로 필드에 접근합니다.
장점: 데이터 무결성을 보호할 수 있고, 메서드 내부에 검증 로직을 추가할 수 있음.
단점: 모든 필드에 무분별하게 제공하면 캡슐화가 깨지고, 외부에서 객체 내부를 지나치게 제어하게 되어 설계가 약해짐.
모든 필드에 getter/setter를 제공하면 문제는?
모든 필드에 대해 접근자를 제공하는 것은 사실상 public
필드와 다를 바 없습니다. 외부에서 객체의 상태를 임의로 변경할 수 있으므로 객체 스스로의 무결성과 책임이 약해집니다. 이는 캡슐화 원칙을 위반하며, 객체의 자율성과 독립성이 깨질 수 있습니다.
getter/setter 대신 어떤 방식으로 캡슐화를 지킬 수 있을까?
실무에서는 모든 필드에 대해 getter/setter를 자동으로 생성하기보다는, 그 객체가 해야 하는 역할(행위)에 맞는 메서드를 정의해서 외부에서 직접 데이터를 조작하지 않도록 만드는 방식으로 캡슐화를 지키게됩니다.
객체의 역할에 맞는 메서드(예: deposit()
, withdraw()
등)를 통해 행위를 추상화하고 상태는 숨깁니다. 이렇게 하면 외부에서는 객체의 내부 구조를 알 필요 없이, 제공된 인터페이스를 통해서만 상호작용할 수 있어 진정한 캡슐화를 구현할 수 있습니다.
이런 방식은 어떤 설계 원칙과 관련이 있을까?
단일 책임 원칙(SRP): 객체는 하나의 책임만 가지며, 그 책임이 변할 이유도 하나여야 한다는 원칙. 각 객체가 자신에게 적절한 동작만을 수행하는 것은 이 원칙을 잘 따르는 것.
또한, **개방-폐쇄 원칙(OCP)**과도 연결됨. 내부 구현을 변경하지 않고 기능을 확장할 수 있도록 돕기 때문.
객체 중심 설계가 유지보수성과 확장성에 미치는 영향?
캡슐화와 단일 책임 원칙을 잘 지킨 객체는 변경이 발생하더라도 영향을 받는 범위가 좁습니다.
예를 들어, 은행 계좌 객체가 deposit()
로직만 바뀌었을 경우, 이 메서드를 사용하는 외부 코드에는 영향을 주지 않기 때문에 시스템의 안정성이 높아지고 유지보수가 쉬워집니다.
객체지향에서 말하는 '다형성(Polymorphism)'이란 무엇인가요? 그리고 다형성이 왜 중요한지 설명해주세요.
다형성(Polymorphism)은 동일한 인터페이스를 통해 서로 다른 구현체를 자유롭게 교체하며 사용할 수 있는 객체지향의 특성입니다. 이를 통해 변경에 유연하고, 확장이 쉬운 시스템을 설계할 수 있으며, 객체 간 결합도를 낮출 수 있습니다.
자바에서는 다형성을 어떻게 구현하나요? 구체적인 예시 코드와 함께 설명해줄 수 있나요?
"Payment" 인터페이스와 그것을 구현한 "CardPayment"와 "KakaoPayPayment" 클래스가 있다고 가정해볼게요. 이 구조를 다형성을 활용해서 설계한다면, 어떤 식의 코드가 될 수 있을까요? 그리고 이 구조가 실제로 어떤 유연함을 제공하는지도 같이 설명해주세요.
클라이언트는 인터페이스를 통해 동작하고, 실제 구현체는 언제든지 바뀔 수 있기 때문에 확장에 매우 유리합니다. 새로운 기능 추가 시 기존 코드를 수정하지 않고 새로운 클래스를 만들어 주입하기만 하면 됩니다.
이렇게 다형성을 잘 활용하는 구조가, SOLID 원칙 중 어떤 원칙들과 연결될 수 있을까요? 연결되는 원칙을 하나 이상 들어보고, 그 이유도 설명해줘.
SRP: 구현체가 자신의 책임만 갖도록 유도
OCP: 새로운 구현체 추가 시 기존 코드 수정 불필요
LSP: 구현체는 언제든지 인터페이스로 교체 가능
ISP: 역할 중심의 세분화된 인터페이스 구조 가능
DIP: 고수준 모듈이 추상화에 의존 → 유연하고 테스트 가능
자바에서 다형성을 사용할 때, instanceof
나 getClass()
를 사용해서 타입을 체크한 뒤 캐스팅해서 사용하는 경우도 종종 있어. 이런 방식은 어떤 문제를 일으킬 수 있을까? 그리고 이걸 객체지향적으로 어떻게 해결할 수 있을까?
instanceof
나 getClass()
를 사용해서 타입을 체크한 뒤 캐스팅해서 사용하는 경우도 종종 있어. 이런 방식은 어떤 문제를 일으킬 수 있을까? 그리고 이걸 객체지향적으로 어떻게 해결할 수 있을까?instanceof
나 getClass()
를 사용하는 것은 다형성 원칙을 무시하고 구체 타입에 의존하게 만들기 때문에 OCP, DIP 위반으로 이어짐.
해결 방법은:
공통 인터페이스에 필요한 동작 정의
템플릿 메서드, 전략 패턴 등의 디자인 패턴 활용
자바에서 다형성의 기반이 되는 개념인 ‘동적 바인딩’이란 무엇인가요? 그리고 이것이 정적 바인딩과 어떻게 다른지도 설명해주세요.
정적 바인딩: 컴파일 타임에 호출 메서드 결정 →
private
,static
,final
동적 바인딩: 런타임에 실제 객체의 타입에 따라 결정 → 오버라이딩된 메서드
다형성이 잘 구현되어 있는 시스템은 테스트 코드 작성에 어떤 이점이 있을까요? Mock 객체나 의존성 주입과 관련해서도 설명해줘.
다형성을 통해 실제 구현체 대신 Mock 객체를 주입하여 독립적인 테스트가 가능함. 특히 의존성 주입(DI)과 결합되면 외부 시스템(DB, API 등)에 의존하지 않는 순수한 단위 테스트 작성이 쉬워짐.
Last updated