[CS] 객체 지향 프로그래밍과 SOLID 원칙

나른한 개발자·2023년 6월 27일
0

CS

목록 보기
7/11

객체 지향 프로그래밍 (OOP)

컴퓨터 프로그래밍 패러다임 중 하나로, 기존 프로그램을 명령어들의 모임으로 봤던 시각에서 벗어나, 여러개의 독립된 단위인 객체들의 모임으로 바라보고자 하는 것이다.

💡 객체란?
프로그램에서 사용되는 데이터 또는 식별자에 의해 참조되는 저장공간을 의미하며, 값을 저장할 변수와 작업을 수행할 메서드를 연관된 것끼리 묶어놓은 것을 말한다.


장점

  • 유연하고 변경 용이한 프로그램을 작성할 수 있다.
  • 코드 재사용을 통해 중복을 없애고 간결하게 표현 가능하다.

단점

  • 객체가 많아지면 용량이 커질수 있다.
  • 설계 시에 많은 시간과 노력이 필요하다.
  • 처리 속도가 상대적으로 느릴 수 있다.

특징

1. 추상화

객체 지향 프로그래밍에서의 추상화는 객체의 공통적인 속성과 특성을 모아서 정의하는 것을 의미한다. 예를 들어 아이폰과 갤럭시는 모두 전화, 메시지, 인터넷이라는 공통 기능이 있다. 이러한 공통점을 이용해 우리는 전화와 메시지, 인터넷이 가능한 객체를 스마트폰이라고 추상화 할 수 있다.

2. 상속

부모 클래스의 속성과 기능들을 하위 클래스에서도 사용할 수 있도록 연장하는 것을 말한다. 예를 들어 전화 기능을 가진 Phone 라는 클래스가 있다고 할 때, 이를 상속 받은 SmartPhone 클래스는 부모 클래스가 가진 전화 기능을 그대로 사용할 수 있으며 하위 클래스의 고유 기능인 인터넷 기능도 추가할 수 있다.

class Phone {
	String model;
    
    void call(){
    	System.out.println("전화를 겁니다");
    }
}


class SmartPhone extends Phone {
	boolean isConnectedToInternet;
    
    void internet(){
    	System.out.println("인터넷 통신을 합니다");
    }
}

3. 다형성

어떠한 객체의 속성이나 기능이 맥락에 따라 다른 역할을 수행할 수 있는 것이다. 다형성을 가장 잘 보여주는 것이 오버로딩오버라이딩이다.

  • 오버로딩: 같은 이름의 메서드가 파라미터의 개수나 자료형에 따라서 다른 기능을 하는 것
  • 오버라이딩: 상위 클래스가 가지고 있는 메서드를 하위 클래스가 재정의 하는 것

다형성은 객체들 간 관계를 유연하게 만들어주며 확장성 있는 설계가 가능하도록 해준다.

4. 캡슐화

클래스 안에 서로 연관되어 있는 속성과 기능들을 하나의 캡슐로 만들어서 데이터를 외부로부터 보호하는 것을 의미한다.
캡슐화의 목적은 코드를 수정없이 재활용하는 것데이터 보호 및 정보 은닉에 있다. 클래스라는 캡슐에 기능들을 담는 것 자체로 1차적으로 캡슐화를 구현할 수 있으며 접근제어자를 이용하여 외부에 노출하지 않아야 할 정보 및 기능의 접근 권한을 제어함으로써 정보를 보호할 수 있다. 또한 접근 제어자를 이용하면 불필요한 수정이 일어나는 것을 막고, 수정이 필요한 경우 책임이 있는 객체만 수정이 일어나도록 할 수 있다.

캡슐화를 실현하는 또 다른 방법은 바로 getter/setter를 이용하는 것이다. 외부에서 멤버 변수에 접근하지 못하게 private으로 변수를 선언하고 해당 변수에 접근하기 위해서는 getter, setter 메서드를 통해서만 접근을 허용해주는 것이다.

어찌보면 public으로 선언했을 때와 똑같이 외부에서 접근 가능한 것처럼 보이겠지만 getter/setter를 이용하면 유효성 검사 또는 예외 처리와 같은 로직을 추가하여 아무 값이나 들어오는 것을 방지할 수 있다.



SOLID 원칙

SOLID 원칙이란 좋은 객체 지향 설계를 위한 5가지 원칙이다.

SRP(Single Responsibility Principle): 단일 책임 원칙

하나의 클래스는 하나의 책임만 가져야한다는 원칙이다. 하나의 책임이라는 것은 하나의 기능만을 담당해야한다는 의미가 아니라 모듈이 변경되는 이유가 한가지여야 한다는 것을 의미한다.

예를 들어 사칙연산 함수를 가진 클래스가 있다고 할 때, 이 클래스가 수정되는 일은 사칙연산 함수와 관련된 문제때문이여야 하지, 다른 이유여서는 안된다.

OCP(Open Closed Priciple): 개방 폐쇄 원칙

확장에 열려있고 수정에는 닫혀있어야한다는 원칙이다. 이는 기존 코드는 변경하지 않으면서 새로운 기능을 추가할 수 있어야한다는 의미이다.

예를 들어 데이터베이스 스펙이 정확히 정해지지 않아 현재는 RDBMS를 사용하다가 추후에 NoSQL로 변경될 가능성이 있다고 해보자. 이때 DB 접근부를 클래스로 바로 구현하기보다 인터페이스와 그것에 대한 구현체를 따로 생성하면 추후에 스펙이 변경되었을 때 변경 스펙에 맞춰 새로운 구현체를 추가해주면 된다.

OCP원칙은 역할과 구현의 명확한 분리와 다형성을 활용함으로써 실현할 수 있다.

LSP(Listov Substitution Priciple): 리스코프 치환 원칙

프로그램의 객체는 프로그램의 정확도를 깨뜨리지 않으면서 하위 타입의 인스턴스로 변경될 수 있어야한다는 원칙이다. 즉, 부모 클래스의 인스턴스가 들어갈 자리에 자식 클래스의 인스턴스가 들어가도 문제없이 작동해야한다.

자식 클래스는 부모 클래스의 책임을 무시하거나 재정의하지 않고 확장만 수행하도록 해야 이 원칙을 준수할 수 있다.

ISP(Interface Segregation Principle): 인터페이스 분리 원칙

이 원칙은 하나의 범용 인터페이스보다 특정 클라이언트를 위한 여러개의 인터페이스가 더 낫다는 것이다. 이 원칙을 준수하면 인터페이스가 명확해지고 대체 가능성이 높아진다.

DIP(Dependency Inversion Principle): 의존 역전 원칙

의존 관계를 맺을 때, 변화하기 쉬운 것 보다는 변화하기 어려운것 또는 변화가 없는 것에 의존하라는 원칙이다. 구체적인 클래스보다 인터페이스 또는 추상 클래스와 의존 관계를 맺으라는 것이다.


지금까지 객체 지향 프로그래밍의 개념과 이를 위한 다섯가지 원칙을 알아보았다. 이 원칙들을 관통하는 개념은 결국 `추상화`와 `다형성`이다. 하지만 이 둘만으로는 클라이언트 코드의 변경이 불가피하기 때문에 DIP, OCP를 만족시킬 수 없다. 스프링에서는 DI 컨테이너 등을 이용해서 객체 지향 언어를 더욱 객체 지향적으로 작업할 수 있게 해준다. 이에 대한 개념은 차차 스프링을 배우면서 보충하도록 하자!


참고
객체 지향 프로그래밍이 뭔가요? (꼬리에 꼬리를 무는 질문 1순위, 그놈의 OOP)
객체 지향 프로그래밍의 4가지 특징ㅣ추상화, 상속, 다형성, 캡슐화
[OOP] 객체지향 프로그래밍의 5가지 설계 원칙, 실무 코드로 살펴보는 SOLID

profile
Start fast to fail fast

0개의 댓글