새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.

3 분 소요

📌 객체지향 프로그래밍과 객체지향 원칙

1. 오늘의 학습 주제

빠밤

객체지향 원칙과 객체지향 프로그래밍(OOP)의 관계에 대해서 자주 잊게되어 다시 복습하려고 합니다.

  • 객체지향 원칙과 객체지향 프로그래밍의 관계에 대한 복습
  • 객체지향 원칙을 사용하는 의미에 대해서 고민해보자

2. 학습 내용

객체 지향 프로그래밍 사용의 의미

피드백 전

소프트웨어 프로그래밍 패러다임에서 객체지향 프로그래밍이 등장한 이유를 생각해봤습니다.

기존 프로시저 프로그래밍은 함수 단위로 문제를 해결하는 방법입니다.

해당 방법은 위에서부터 아래로 읽어가며 현실 세계의 문제를 함수 단위로 나누어 해결하는 방식입니다

그런데 함수 단위로 하다보니 빠르게 변하는 클라이언트 요구사항에 맞춰 코드를 변경하기 어려워졌습니다.

함수 단위로 관심사를 분리한고 구조체로 나누어 처리한다고 하더라도 결국은 구현체를 의존하는 패러다임입니다.

모듈을 나눈다고 하더라도 모듈을 직접의존하게 되다보니 추가 요구사항이나 변경에 대해 유연성이 떨어지고 코드 전체를 바꾸게 됩니다.

그래서 객체지향 패러다임이 등장합니다.

클래스의 역할에 의존하고, 클래스 끼리 통신을 하여 문제를 해결하는 방식입니다.

이러헥 하다보니 계층을 나눌 수 있고 모듈을 구현체가 아닌 역할에 의존할 수 있어서

똑같은 역할의 기능을 구현한 다른 객체로 쉽게 변경이 가능하다보니 확장과 유지보수에 유리하게 되었습니다.

객체지향을 사용한다는 의미는 클래스 레벨에서 구현체를 의존하는게 아닌 역할에 의존하도록 도와주는 인터페이스나 추상 클래스를 의존하는 방법입니다.

이런 기능을 제공하는 것이 객체지향 프로그래밍의 꽃인 다형성이며

다형성을 활용할 수 있도록 도와주는 것이 상속과 구현입니다.

그리고 내부 로직을 변경하지 못하고 외부에서 공개한 인터페이스만 사용하도록 하여 모듈의 응집도를 높이는 캡슐화도 장점입니다.

보완할 점

  1. 객체지향의 목적 설명 보완:

    왜 역할에 의존해야하는지, 왜 다형성이 중요한지에 대한 설명이 더 필요합니다.

    예를 들어, 역할에 의존해야 유지보수성과 확장성이 높다는 점을 구체적으로 언급하면 설득력이 높아집니다.

  2. 개념 연결이 부족합니다.

    캡슐화와 다형성이 어떻게 유지보수성과 확장성에 기여하는지 연결해야합니다.

    예를 들어, 캡슐화는 내부 구현을 숨겨 변경에 유연하게 해주고, 다형성은 코드 수정을 최소화하면서 확장할 수 있다는 점입니다.

  3. 상속의 단점 언급이 부족합니다.

    상속은 잘못 사용하면 결합도를 높이고 유지보수를 어렵게 만들 수 있습니다.

    구현보다 인터페이스 상속을 권장하는 이유를 언급해야합니다.

지피티 개선제안

  1. 객체지향의 목적 추가 설명이 필요하다

    역할에 의존하면 유연성과 유지보수성이 높아진다.는 점을 구체적으로 설명해달라고합니다.

    역할에 의존하면 새로운 요구사항이 생길 때 기존 코드를 수정하지 않고 기능을 확장하할 수 있습니다.

    이는 유지보수성과 확장성을 높여주며, 변경에 유연한 설계를 가능하게 합니다.

  2. 개념 연결 및 트레이드 오프 설명

    • 갭슐화, 다형성, 상속이 확장성과 유지보수성에 어떻게 기여하는지 구체적으로 설명.

    다형성을 사용하면 기능 변경 시에도 인터페이스만 유지하면 되므로, 코드 수정 최소화와 확장성을 동시에 달성할 수 있습니다. 하지만, 상속 남용 시 결합도가 높아지고 유지보수가 어려워질 수 있으므로, 구현 상속보다는 인터페이스 상속을 권장합니다.

프로시저 프로그래밍의 한계

프로시저 프로그래밍은 함수 단위로 문제를 해결하는 방식입니다.

코드를 위에서 아래로 읽어가며 순차적으로 실행되며, 함수 단위로 관심사를 분리하여 문제를 해결합니다.

프로시저 프로그래밍은 구현체에 의존하며, 모듈이 직접 의존하기 때문에 유연성이 떨어지고 변경에 취약합니다.

이를 해결하기 위해서 객체지향 프로그래밍이 등장합니다.

oop는 클래스의 역할에 의존하고, 객체 간 메세지 전달로 문제를 해결하는 방식입니다.

이때 역할에 의존한다는 것은 구현체가 아닌 역할(인터페이스 또는 추상 클래스에) 의존하는 것을 의미합니다

객체지향 설계에서 주의할점: 트레이드 오프 !!!!!

객체지향 설계는 유연하고 유지보수성이 높은 코드를 작성할 수 있습니다.

남용하거나 과도하게 추상화하면 오히려 코드 가독성이 떨어지고 유지보수가 어려울 수 있습니다.

상속의 단점

상속은 코드 재사용성을 높입니다, 잘못 사용하면 결합도가 높아져 유지보수가 어렵습니다.

특히, 구현 상속을 남용하면 하위 클래스가 상위 클래스를 강하게 의존하여 변경에 취약해집니다.

따라서, 구현 상속보다는 인터페이스 상속을 사용하고, 구성을 우선하는 것이 좋습니다.

상속은 특수할 경우 장점이 있다고 생각한다.

상속의 단점은 하위 클래스가 상위 클래스의 변경에 취약하다는 점입니다.

그러면 반대로 상위 클래스의 변경이 하위 클래스에도 영향을 미쳐야하는 경우

모두 동일한 비즈니스 레벨을 갖는다고 한다면 상속이 오히려 공통 로직에 대해 수정사항이 적어 질 수 있다고 생각이 듭니다.

예를 들어

상위 클래스 = 카드결제

하위 클래스는 = 삼성카드, 롯데카드 등으로 확장된 클래스라면 상속의 장점을 살릴 수 있지 않을까 싶습니다.

다시 돌아와서 객체지향과 원칙의 관계

객체지향 프로그래밍은 문제 해결을 객체화해서 확장성과 유지보수를 편하게 패러다임입니다.

객체지향 원칙은 OOP의 목표를 달성하기 위한 구체적인 방법론중 하나입니다.

관계 정리

객체지향 프로그래밍은 현실 세계의 문제를 객체 단위로 해결 〉확장성, 유지보수성, 재사용성을 높인다.

수단: 클래스, 상속, 객체, 다형성, 캡슐화, 추상화 등

객체지향 원칙(SOLID)등

방법: OOP의 목표를 효율적으로 달성하기 위해서 구체적인 설계 지침을 말한다.

목표: 코드의 응집도를 높이고 결합도를 낮추며, 변경에 유리한 설계를 만들도록 도움을 준다.

객체지향 원칙 빠르게 기억하기

SRP(단일 책임 원칙): 하나의 클래스는 하나의 책임만 갖는다.

핵심 키워드: 하나의 책임, 응집도, 변경 이유도 하나

목적: 변경 발생 시 영향을 최소화

예: User.class에서 “로그인”, “회원가입”등은 서로 다른 책임으로 분리

OCP(개방-폐쇄 원칙): 확장에는 열려있고, 수정에는 닫혀있다.

핵심 키워드: 확장 가능, 수정금지, 다형성

목적: 기존 코드 변경없이 기능 추가 가능

예: 인터페이스를 사용해 기능 확장

LSP(리스코프 치환 법칙) : 자식 클래스는 부모클래스를 대체할 수 있어야한다.

핵심 키워드: 치환 가능성, 상속, 다형성

목적: 상속받은 객체가 부모 객체처럼 사용되도록 보장

예: Animal 부모를 상속한 Dog, Cat 클래스가 부모 클래스의 메서드를 오버라이딩 할 때 기능이 일관성있어야한다.

ISP(인터페이스 분리 원칙): 하나의 인터페이스는 하나의 역할만 가져야한다.

핵심 키워드: 작은 인터페이스, 구체화 , 유연한 의존성

목적:불필요한 의존성 방지

예: UserAction 인터페이스를 LoginAction, SignupAction 등으로 세분화

DIP(의존 역전 원칙): 고수준의 모듈은 저수준 모듈에 의존하면 안된다.

핵심 키워드: 추상화 의존, 디커플링, 인터페이스

목적: 의존성 주입을 통한 유연한 구조

예: PaymentServices는 PaymentProcesser 인터페이스에 의존하고, CreditCardProcessor 등을 사용한다.

여기서 인터페이스의 위치가 중요하다

인터페이스의 위치가 구현체에 간다면 패키지는 하나의 모듈라고 생각한다.

따라서 상위 인터페이스는 구현체와 같은 위치 패키지에 두는것이 아니라

image-20250223185206286

인터페이스가 상위 클래스에 있어야 DIP가 유지가 된다.

댓글남기기