본문 바로가기
Java

[Java] SOLID 원칙

by jinjin98 2022. 10. 3.

̱ SOLID

 

SOLID 원칙은 아래 5가지 원칙의 앞 자리 알파벳을 합쳐 부르는 이름입니다.

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

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

LSP(Liskiv Substitution Principle): 리스코프 치환 원칙

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

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

 

하나씩 알아보겠습니다.

 

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

한 클래스에는 하나의 책임만 가져야 합니다

변경이 있을 떄 파급 효과가 적어야 합니다.

 

public class Animal {

    String type;

    public Animal(String type) {
        this.type = type;
    }

    public String move() {
        if (type == "호랑이") {
            return "호랑이는 네 발로 이동";
        } else {
            return "독수리는 두 날개로 이동";
        }
    }
}

 

Aninal 이라는 클래스에서 어떤 동물이냐에 따라  move() 메서드의 처리를 다르게 했습니다.

Aninal 클래스에서는 호랑이 역할과 독수리 역할을 모두 하고 있습니다.

즉 현재 하나의 클래스에서 두 가지의 책임을 가지고 있는 것입니다.

이렇게 되면 SRP 를 위배하는 것입니다.

Aninal 클래스를 부모 클래스로 만들어 공통 코드를 Aninal 클래스에 두고

Tiger 클래스와 Eagle 클래스를 만들어 Aninal 클래스를 상속한 후

차이점만 각자 구현하게 하면 SRP를 지킬 수 있습니다.

 

public abstract class Animal {

    public abstract String move();
}

 

public class Tiger extends Animal{

    @Override
    public String move() {
        return "호랑이는 네 발로 이동";
    }
}

 

public class Eagle extends Animal{

    @Override
    public String move() {
        return "독수리는 두 날개로 이동";
    }
}

 

호랑이와 독수리의 책임을 분리했습니다.

각 클래스를 보면 단 하나의 책임만 갖고 있어 응집도는 높고

다른 책임과의 의존과 연관이 존재하지 않아 결합도가 낮다는 것을 확인할 수 있습니다.

이렇게 하면 새로운 동물이 계속 생길 때, 이 각각의 클래스에는 변경이 없고 새로운 클래스를 정의하면 될 것입니다.

 

2. OCP(Open Closed  Principle): 개방 폐쇄 원칙

소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 합니다.

다형성을 활용합니다.

인터페이스나 부모 클래스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현합니다.

위의 예제 코드에서 바로 적용할 수 있는 원칙입니다.

새로운 동물이 생긴다해도 다음과 같이 다른 클래스의 변경 없이

단순히 새로운 동물에 대한 클래스를 추가하기만 하면 됩니다.

 

public class Shark extends Animal{

    @Override
    public String move() {
        return "상어는 지느러미로 이동";
    }
}

 

개방 폐쇄 원칙을 무시하고 프로그램을 작성하면 객체 지향 프로그래밍((Object Oriented Programming) 의

가장 큰 장점인 유연성, 재사용성, 유지보수성 등을 얻을 수 없습니다.

따라서 객체 지향 프로그래밍에서 개방 폐쇄 원칙은 반드시 지켜야 할 원칙입니다.

 

3. LSP(Liskiv Substitution Principle): 리스코프 치환 원칙

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

즉 자식 클래스의 인스턴스는 부모 클래스 타입의 참조 변수에 대입해

부모 클래스의 인스턴스 역할을 하는데 문제가 없어야 합니다.

예를 들면 위의 예제 코드처럼 Animal 타입의 참조 변수에 동물중 하나를 클래스로 가진 객체는 대입이 가능하지만

동물의 역할을 하지 못하는 식물 종류인 장미, 소나무 클래스 객체를 생성해 넣으면 안된다는 것입니다.

 

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

자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안 됩니다.

큰 틀로 되어있는 인터페이스를 구체적인 작은 틀로 분리해야 합니다.

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

즉 위의 예제 코드에서 Animal 클래스를 인터페이스로 만들고 분리한다면

포유류, 조류, 어류로 분리할 수 있습니다.

이렇게 구체적으로 분리하면 인터페이스가 명확해지고, 대체 가능성이 높아집니다.

 

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

추상화 된 것은 구체적인 것에 의존하면 안 됩니다. 구체적인 것이 추상화된 것에 의존해야 합니다.

자주 변경되는 구체 클래스에 의존하면 안 됩니다.

쉽게 말해서 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 의미입니다.

인터페이스에 의존하는 이유는 구현 클래스보다 코드가 변할 가능성이 낮기 때문입니다.

 

SOLID 원칙을 적용하다 보면 소스 파일의 개수가 더 많아지는 경향이 있습니다.

하지만 이렇게 많아진 파일이 논리를 더욱 잘 분할하고, 잘 표현하기에 이해하기 쉽고, 개발하기 쉬우며,

유지보수하기 쉬운 코드가 만들어집니다. SOLID 원칙을 적용함으로써 얻는 혜택에 비하면 늘어나는 

소스 파일 개수에 대한 부담은 충분히 감수하고도 남을 만합니다.

 

이 포스팅은 자바 객체 지향의 원리와 이해의 내용을 참고하여 작성하였습니다.

'Java' 카테고리의 다른 글

[Java] JVM 메모리 구조  (0) 2022.10.25
[Java] this 와 this() super 와 super()  (0) 2022.10.25
[Java] 추상클래스(Abstarct Class) 인터페이스(Interface)  (0) 2022.10.25
[Java] 열거형 타입 Enum  (0) 2022.10.22
[Java] Optional<T>  (0) 2022.10.10

댓글