본문 바로가기

Programming/Clean Code

SOLID원칙

반응형

SOLID원칙이란 객체지향(Object Oriented Programming)에서 꼭 지켜야 할 5개의 원칙을 말한다

5개의 원칙 앞 글자를 따서 SOLID라고 부른다.



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


Responsibility‘reason to change’로 변경되어야 할 이유를 뜻한다

, 어떤 class가 변경되어야 하는 이유는 오직 하나뿐이어야 한다는 원칙이다.

 

나무위키에 나와있는 예)

사칙연산 기능을 하는 계산 클래스가 있다. 현재 상태의 계산 클래스는 오직 사칙연산 기능만을 책임진다

이 클래스가 변경(수정)될만한 사유는 사칙연산 함수와 관련 된 문제 뿐이다

단일 책임 원칙을 지켰기에 클래스의 목적이 명확해졌고, 그에따라 구조가 난잡해지거나 수정 사항이 불필요하게 넓어지는 것을 예방했다.


만약 위의 원칙이 지켜지지 않는다면 어떻게 될까?

어떤 프로그래머가 이 계산 클래스를 통해 GUI를 가지는 계산기 프로그램을 개발하고 있다

그런데 중간에 귀찮아서 GUI 관련 코드를 계산 클래스에 넣어버렸다. 그러면 단일 책임 원칙이 깨지게 된다

계산 클래스는 2개의 책임을 가지게 된다. GUI기능 책임, 사칙연산 책임. 수정 할 때 영향을 받는 범위가 

커졌고 무엇보다 클래스의 목적이 모호해지는 문제가 생겼다.




2.    Open-Closed Princible (OCP, 계방-폐쇄 원칙)


기존의 코드를 변경하지 않으면서(Closed) 확장(새로운 기능)은 쉽게 되어야 한다(Open)

수정에 대해서는 폐쇄하고, 확장에 대해서는 개방하는 원칙이다.

 

예제 코드를 보면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class VideoPlayer
{
    public void play()
    {
        System.out.println(“Play avi”);
    }
}
 
public class Client 
{
    public static void main(String[] args)
    {
        VideoPlayer player = new VideoPlayer();
        player.play();
    }
}
 
cs

 동영상을 재생해주는 VideoPlayer class가 있다. 

classplay() method를 통해 avi확장자 동영상을 재생시켜준다

어느 날 갑자기 mp4확장자 동영상도 재생을 시켜야 하도록 요구사항이 바뀌었다

요구사항을 만족하기 위해서는 play() method를 수정하여야 한다

그러나 기존의 code를 변경하는 것에 대해 close가 되어 있으므로 OCP 원칙이 깨져버리게 된다.

고로, OCP원칙을 지키기 위해서는 애초에 확장자가 변경될 수 있음을 미리 인지하고 아래 코드와 같이 설계를 했어야 했다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
interface videoPlay
{
    public void play();
}
 
class VideoPlayer
{
    private videoPlay file; 
 
    public void setFile(videoPlay file)
    {
        this.file = file;
    };
   
    public void play()
    {
        file.play();
    }
}
 
class Avi implements videoPlay
{    
    public void play()
    {
        System.out.println(“Play avi”);
    }
}
 
public class Client
{
    public static void main(String[] args)
    { 
        VideoPlayer player = new VideoPlayer();
 
        player.setFile(new Avi());    // player.setFile(new Mp4()); 
        player.play();
    }
}
cs

애초에 이렇게 설계를 하고 구현을 해놓았으면 요구사항이 변경되더라도 mp4 class를 새로 만들어 

기존의 class는 변경 없이도 요구사항을 만족시킬 수 있게 된다.

 

정리하면, 바뀔 가능성 있는 것들은 애초에 확장성 있게 구현을 하여야 한다.

 



3.    Liskov Substitution Principle (LSP, 리스코프 교체 원칙)


LSP는 상속과 관련이 있는 원칙이다. 자식 class는 항상 부모 class를 대체할 수 있다

쉽게 말해 부모 class object 자리에 자식 classobject를 넣어도 잘 동작하여야 한다는 말이다.

, 부모가 될 class를 설계할 때에는 일반적으로 설계하여야 한다.




4.    Interface Segregation Principle (ISP, 인터페이스 분리)


ISP는 어떤 객체에서 사용하지 않는 method는 그 객체에 포함되지 않아야 한다는 원칙이다.

자신이 사용하지 않는 method는 상속받지 않도록 하는 것이다.

Animal interface가 있다. 해당 interface에는 run(), fly(), eat().. 등등의 method가 있다 할 때

해당 interface를 사용하는 Tiger class는 실제로 fly()가 필요없음에도 불구하고 fly()를 구현해주어야 하는 문제가 생긴다.

ISP를 지키기 위해서는 Animal interface를 쪼개서 2개 혹은 그 이상으로 interface들을 만들어 준다. (다만 그렇다고 또 너무 작게 여러 개로 쪼개지는 말자..)

 



5.    Dependency Inversion Principle (DIP, 의존 역전 원칙)


마지막 DIP는 상위 class는 하위 class에 종속되어서는 안되며, 둘 다 추상적인 것에 의존해야 한다는 것이다

구체적은 것은 자주 변화가 일어나기 때문에 변화가 적은 추상화된 것에 의존하는 것이 좋다. , 추상 클래스나 인터페이스에 의존하라는 말이다.

 

자동차 라는 abstract class를 두고, BMW, BENZ 등등의 class들이 이를 상속한다

그럼 사람 class는 자동차 abstract class에 의존하여 코드를 확장성 있게 할 수 있다.

반응형