들어가기 전에..

해당 글은 Inflearn(https://www.inflearn.com/)에서 제공하는 김영한 개발자 님의 스프링 핵심 원리 - 기본편(https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard)를 듣고 제가 학습한 내용을 정리한 내용입니다. 학습 내용의 모든 출처는 해당 강의에 있습니다.

SOLID 원칙

SOLID란 클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙(SRP, OCP, LSP, ISP, DIP)의 앞 글자를 따서 만든 용어이다.

SOLID 원칙을 알아야하는 이유는 시스템에 새로운 기능이 확장되거나 변경사항이 있는 경우 기존 기능들이 영향을 적게 받는 것이 좋은 설계이기 때문이다.


1) SRP(Single Responsibility principle), 단일 책임 원칙

소프트웨어의 설계할 때 객체는 단 하나의 책임만 가질 수 있다.

객체가 하나의 책임을 가진다는 것은 새로운 기능이 확장되거나 변경사항이 있는 경우 파급효과가 적다면 하나의 책임을 가지고 있는 것이다.

즉, 객체 간의 응집도는 높고 결합도가 낮은 프로그램이라는 뜻으로 해석할 수 있다.

class Calculator{
	public void add(int a, int b){...}   //요리하기
	public void sub(int a, int b){...}   //청소하기
	public void mul(int a, int b){...}   //작업하기
	public void div(int a, int b){...}   //제출하기
}

Calculator클래스는 사칙연산에 대한 기능만 가지고 있어야한다.

계산기가 추후에 다른 기능을 지원한다해서 계산기에 사칙연산 이외의 기능을 추가한다면 이는 응집도가 낮아지고 메소드간의 결합이 강해질 것이다.

따라서, Calculator클래스가 사칙연산의 기능만을 가지는 것은 하나의 책임을 갖는다고 할 수 있고 이는 SRP를 잘 지켰다고 할 수 있다.


2) OCP(Open/Closed Principle), 개방 폐쇄 원칙

소프트웨어가 기존의 코드를 변경하지 않고(Closed) 확장(Open)할 수 있다.

인터페이스 안에 필요 기능을 작성한다면 인터페이스를 구현하는 구현클래스는 다형성을 통해서 새로운 기능의 확장이 가능하다.

//Car 인터페이스
public interface Car {
	public boolean isHybrid();
}

//Bus 구현 클래스
public class Bus implements Car {
	@Override
	public boolean isHybrid() {
		return false;
	}
}

//Bus 구현 클래스
public class Truck implements Car {
	@Override
	public boolean isHybrid() {
		return true;
	}
}

Car인터페이스가 있고, Bus와 Truck 구현 클래스가 있다. 하이브리드 차인지 확인만 하고 싶은 클라이언트는 구현 클래스만 선언해서 호출하면 된다.

Car bus = new Bus();
Car truck = new Truck();

bus.isHybrid();
truck.isHybrid();

다른 경우를 확인해보자.

//Car car = new Bus();
Car car = new Truck();

클라이언트가 Bus에 대한 구현 클래스 기능을 사용하다가 Truck에 대한 구현 클래스 기능을 사용하고자 한다면 기존의 코드가 변경된 것이 아닌가?라는 의문점이 생길수 있다.

클라이언트가 직접 구현 클래스를 선택하기 때문에 클라이언트 코드의 변경이됨을 확인할 수 있다.즉, 다형성을 이용했지만 OCP 원칙이 깨지는 현상이 발생한다.

따라서, 객체를 생성하고 연관관계를 맺어주는 별도의 조립, 설정자가 필요한데, Spring Framework는 Spring Container가 이 역할을 담당한다.


3) LSP(Liskov substitution principle), 리스코프 치환 원칙

클래스를 상속하는 자식 클래스들은 부모 클래스의 규약을 지켜야한다.

속력을 10 증가시키는 accel이라는 메소드를 가진 Car클래스가 있다.

public class Car {
	public void accel(int speed) {
		speed += 10;
	}
}

Car 클래스를 상속하는 자식 클래스가 accel이라는 메소드를 오버라이딩하여 속력을 20 감소시켜 뒤로 액셀을 밟게 구현했다고 가정하자.

public class MiniCar extends Car{
	@Override
	public void accel(int speed) {
		speed -= 20;
	}
}

이러한 경우, 컴파일에서의 문제가 생기지는 않지만, 부모 클래스(Car)가 규정하고 있는 accel의 기능을 무시하는 경우이다. 이때 LSP에 위배되었다고 정의한다.

따라서, 부모클래스를 상속하는 자식클래스는 부모 클래스의 규약을 무시하거나 오버라이딩을 자제해야하는 것이 LSP이다.


4) ISP (Interface Segregation principle), 인터페이스 분리 원칙

어떤 구현 클래스는 자신이 구현하지 않는 인터페이스는 사용하지 않아야한다.

interface People {
	public void cook();     //요리하기
	public void cleaning(); //청소하기

	public void work();     //작업하기
	public void submit();   //제출하기
}

People 인터페이스는 cook(), cleaning(), work(), submit()이라는 기능을 정의한 인터페이스이다.

기능을 자세히 보면, cook() 과 cleaning()은 주부가 하는 역할이고, work()와 submit()은 직장인이 하는 역할이다. 이렇게 일반적인 인터페이스(people)을 구체적인 여러 인터페이스(Housewife, Worker)로 나눠주는 것이 객체지향적인 관점에서 더 좋은 설계이며 ISP를 잘 지킨 설계이다.

//주부 인터페이스
interface Housewife {
	public void cook();
	public void cleaning();
}

//직장인 인터페이스
interface Worker {
	public void work();
	public void submit();
}

5) DIP(Dependency inversion principle), 의존 관계 역전 원칙

구현체보다는 인터페이스나 추상 클래스에 의존하는 것이 좋다.

클라이언트가 기능을 이용할 때 인터페이스의 기능만 알고 그 안을 구현하는 구현체에 대해서는 몰라도되는 것과 비슷한 원리이다.

구현체보다 인터페이스나 추상 클래스에 의존해야 기존 기능의 변경이나 새로운 요구사항을 통한 기능 확장이 되었을 때 유연한 변경이 가능하다.

여기서 OCP는 인터페이스와 구현체 둘다 의존하는 것을 알 수 있는데, 이는 DIP를 위반하는 것으로 볼 수 있다.

즉, 객체 지향 설계의 핵심은 다형성이지만, 다형성만으로는 OCP, DIP를 위배하는 경우가 발생한다.

Spring Framework는 스프링이 지원하는 의존성 주입 (DI,Dependency Injection)과 DI 컨테이너를 이용해 자바 객체의 의존성을 연동해준다.


정리

  • 어떠한 개발에 있어서도 인터페이스나 추상 클래스를 통해서 기능을 상세하게 잘 설계한다면 개발 환경이 변경되어도 필요할 때에 구현체를 바꿔주는 것이 가능하고 확장이 가능하다. 하지만, 인터페이스의 무분별하게 사용한다면 추상화라는 비용이 발생하기 때문에 기능 확장의 가능성이 없다면 굳이 인터페이스를 무리하게 사용할 필요는 없다.

Reference

Inflearn 김영한 님의 스프링 핵심 원리 - 기본편 https://www.inflearn.com/course/스프링-핵심-원리-기본편/dashboard

SOLID 원칙 https://medium.com/@hckcksrl/solid-원칙-182f04d0d2b

SOLID 원칙 https://victorydntmd.tistory.com/291https://dev-momo.tistory.com/entry/SOLID-원칙

SOLID 원칙 https://velog.io/@hanblueblue/Java-SOLID-SRP-OCP-LSP-ISP-DIP

profile
백엔드 개발자 지망생입니다!

0개의 댓글