본문 바로가기

back-end/spring

spring 선수 지식/ 객체지향 SOLID

객체 지향 프로그래밍 OOP; Object Oriented Programming

여러 개의 독립된 단위 '객체'들을 조립해서 완성된 프로그램을 만드는 것을 목표로 한다. 객체를 사용하면 프로그램의 변경이 발생할 때 개별의 객체만 갈아 끼우듯이 사용하는 것이 가능하기 때문에 유연한 개발이 가능하다.

다형성 Polymorphism

우리가 라면을 먹을 때 신라면, 진라면, 열라면 등의 여러 종류의 라면을 골라서 먹을 수 있다. 어떤 라면을 선택해서 먹든 선택한 라면을 구성하는 재료는 알 필요 없이 조리해 먹을 수 있고 이는 새로운 라면이 출시되더라도 동일하다. '라면'이라는 틀만 유지한다면 새로운 라면을 먹기 위해서 라면을 조리하는 방법, 먹는 방법들을 새로 알 필요가 없는 것이다.

이것은 라면이 하나의 큰 '역할'을 하고 구체적인 신라면, 진라면, 열라면 등이 라면을 구현하고 있기 때문에 가능하다.

 

public class Person {
    private Ramen ramen = new ShinRamyun;
}

 

프로그래밍에서 이러한 역할을 인터페이스, 구현을 인터페이스를 구현하는 클래스, 즉 구현 객체로 나누어 볼 수 있다. 역할과 구현으로 나누면 설계된 프로그램을 클라이언트가 사용할 때, 구현 클래스 대신 대상의 역할, 즉 인터페이스만 인지하면 구현 클래스의 내부 구조를 알지 못해도 프로그램을 사용할 수 있다. 또한, 구현 클래스의 내부 구조나 구현 클래스 자체가 변경되더라도 클라이언트는 영향을 받지 않으면서 기존의 인터페이스를 그대로 사용할 수 있다.

 

이는 곧 프로그램 실행 시점에 인터페이스를 구현하는 클래스를 유연하게 변경할 수 있게 해줌으로써 클라이언트에 영향 없이 서버의 구현 기능을 유연하게 변경할 수 있게 해준다는 것을 말한다.

즉, 다형성으로 인해 프로그램을 단순화하고 유연성을 높일 수 있고, 프로그램의 변경 역시 용이해지는 것이다.

 

객체 지향 설계의 5가지 원칙 SOLID

1. 단일 책임 원칙 SRP; Single Responsibility Principle

한 클래스는 하나의 책임만 가져야 한다.

하나의 책임은 클 수도 작을 수도 있지만, 신경 써야 할 것은 변경에 따른 파급 효과를 고려하는 것이다. 즉, 한 부분을 변경하는데 그로 인해 고쳐야 할 것이 많이 발생한다면 SRP를 잘 지켰다고 말하기 힘들다. 

 

2. 개방-폐쇄 원칙 OCP; Open/Closed Principle

소프트웨어 요소는 확장에 열려 있고 변경에 닫혀 있어야 한다.

public class Person {
    //private Ramen ramen = new ShinRamyun;
    private Ramen ramen = new JinRamen;
}

위와 같이 인터페이스를 사용하는 경우 Ramen 인터페이스를 구현하는 클래스를 여러 개 만드는 것이 가능하므로 Ramen 인터페이스는 확장에 열려 있다. 하지만 구현 클래스를 변경하고자 하는 경우 소스 코드의 변경이 일어난다. 자바 코드로 구현 불가능한 OCP를 추후 스프링을 통한 의존 관계 주입으로 해결한다.

 

3. 리스코프 치환 원칙 LSP; Liskov Substitiution Principle

객체는 프로그램의 정확성을 깨트리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.

다형성 구현 시 구현 클래스가 인터페이스의 규약을 모두 지키면서 설계되어야 한다는 것을 말한다. 컴파일이 되는 것은 물론이고, 내부적인 규약 역시 지켜야 한다. 예를 들어 Ramen 인터페이스에 불닭볶음면 같은 볶음 라면을 넣는 것은 규약 위반이다. 라면은 물을 버리지 않고 550ml만큼의 물로 조리되지만 불닭볶음면 같은 볶음 라면은 그런 식으로 조리될 수 없기 때문이다.

 

4. 인터페이스 분리 원칙 ISP; Interface Segregation Principle

특정 클라이언트를 위한 인터페이스 여러 개 가 범용 인터페이스 하나보다 낫다.

조리사 클라이언트와 연구자 클라이언트가 존재한다고 하자. 라면 인터페이스를 조리 인터페이스와 재료 인터페이스로 분리하면 재료 인터페이스가 변경이 되더라도 조리사 클라이언트는 조리 인터페이스만 사용하므로 변경에 영향을 받지 안흔다.

즉, 인터페이스가 명확해지고 대체 가능성이 높아진다. 

 

5. 의존관계 역전 원칙 DIP; Dependency Inversion Principle

추상화에 의존해야지 구체화에 의존하면 안 된다.

구현 클래스에 의존하지 말고 인터페이스에 의존하라는 것을 의미한다. 의존한다는 것은 클라이언트 측에서 구현 클래스를 몰라야 한다는 말과 동일하다.