객체지향 5원칙(SOLID)은 무엇일까?

 

 

 

 

 

객체지향 5원칙(SOLID)은 무엇일까?


우리가 객체지향 프로그래밍을 할때 알아두면 좋은 5가지 원칙에 대해서 알아보겠다

우선 이글을 보기전에 기본적인 프로그래밍 문법에 대해서 알고있어야 이해하기 편하니 이점 주의해주길 란다

 

첫번째로 SSRP(Single Responsibility Priciple) 단일 책임 원칙으로써,

이게 무슨말이냐면 하나의 클래스는 하나의 기능만 담당해야 한다는 의미를 말한다

하나의 기능.. 어디서부터 어디까지 하나의 기능이라고 정의하기 애매한 말인데

 

이걸쫌 다르게말해보면 만약 어떤 기능을 손봐야할 이유가 생기면 해당하는 클래스는 그 기능에대한 책임만 가진다는 의미로 받아들이면 될꺼같다

 

예를들어 하나의 클래스가 A와 B라는 책임을 가진다고 가정해본다면

만약 사용자의 피드백에 따라서 A라는 피드백이 오게되면 그 클래스를 수정하고 또 B라는 피드백이오면 또수정해야한다 이는 단일책임 원칙에 위배되는 것으로 하나의 클래스는 하나의 책임만 지도록 설계를 해야한다

 

사용자의 정보를 저장하는 로직이 있다고 생각해보면 사용자의 정보는 사용자 이름, ID, PASSWORD라는 인스턴스로 분류한뒤 정보를 저장하는 save라는 메서드와 ID를 통해 이름을 찾는 findName 이라는 메서드 두개가 있다고 생각해보면 save는 정보를 저장하는 로직'만' finName은 이름을찾는 로직'만' 담당하게된다

 

위처럼 로직을 단일책임원칙으로 분류하게되면 추후에 수정할사항이 생겨도 해당하는 클래스 로직'만' 수하면된다

 

 

 

 

단일책임원칙에 예를 코드로 한번 설명해보자 Member라는 클래스는 id, name, pwd라는 사용자 정보 3가지를 가진다 그리고 생성자와 getter setter를 이용해서 값을 넣고 얻을수있게 하는데

 

 

 

위에서 만든 Member 회원 객체를 통해서 저장소를 만들고 Hash에다가 저장하기로했다 여기서 save라는 구현체는 save라는 기능'만' 수행하고 findName 구현체는 id가 들어오면 해당 id에 속하는 member 객체를 반환하는 기능'만' 담당한다

 

만약 이게 무슨말인지 모르겠다면 자바기본을 다시한번 보고오면 이해하기 쉬울것이다 위에서 보듯이 하나의 메서드는 하나의 책임만 지는것이 SRP 단일책임원칙이다

 

 

그다음 두번쨰로는 OCP개방 폐쇄의 원칙으로써 프로그램은 확장에는 열려있되, 수정에는 닫혀있어야 다는 것이다 한마디로 여러 기능을 추가하기에는 쉽지만 기능을 추가하는 과정에서 기존 비즈니스로직들을 정하는것은 OCP위배라는것이다

 

 

 

예를들어 위에서 만든 코드를보면 MemberRepository는 인터페이스로써 MemberRepositoryImpl가 구현하있다

근데 위에서 적은 코드는 그냥 해쉬맵을 통해 메모리에 단순 저장한것으로 추후에 관계형 데이터베이스나

NoSQL방식으로 저장한다고 바뀐다면 DBMemberRepository를 구현한뒤 가르키면 끝이다

 

기존에 구현체는 전혀 신경을 쓰지않아도 된다는것이다 만약 기능추가중에 기존구현체를 변경하게된다면 이것은 OCP 위배라고 볼수있다

 

그다음 3번째 LSP 리스코프 치환원칙하위타입은 상위타입으로 대체될수있어야 된다는 말이다 이걸 쉽게 풀어보자면 만약 정사각형을 직사각형이다 라는 예시를 들어보면된다

 

정사각형은 넓은 의미에서 보면 결국 직사각형이므로 정사각형을 구현한 클래스를 상속받아

직사각형을 빠르게 구현할수 있을것이다 이처럼 하위타입은 상위타입으로 교체해도 문제가 발생하지 않는 는것이다

 

 

 

그다음 4번째 LSP 인터페이스 분리원칙하나의 인터페이스보다는 좀더 세분화된 여러개의 인터페이스가더좋다

라는것이다 이게무슨말일까?

 

 

MemberRepository는 말그대로 Member클래스를 가지고 저장, 조회하는 역할을 가진 인터페이스다

다른기능은 하지않고 오로지 저장과 조회를 담당한다고 볼수있는데

 

여기에서 만약 추가기능으로 쇼핑을 하는 기능을 추가해야된다고 가정해보면 내가 살려는 물품이름, 물품가격, 정보 등을 가지고있는 클래스를 만들고 역할을 하는 인터페이스와 그것을 구현하는 구현체를 만드는것이다

 

약간 1번과 비슷한말인데 인터페이스또한 책임에따라서 여러개로 분리시키는것이 더 좋다는 이야기이다

 

그다음 마지막으로 내가 가장 중요하다고 생각하는 의존역전원칙 DIP이다

DIP는 로직들을 구현함에있어서 오로지 인터페이스와 추상화에만 의존하고 구현체에는 의존하지 않는다는것이다

 

 

 

위에 서술한 코드에서 추가로 MemberService라는 클래스를 만들었는데 이는 위에서 저장소를 통해 실제 사용자가 register를 호출하면 저장소에 담기게되는데 여기서 중요한점은 위에 memberRepository = new MemberRepositoryImpl(); 이부분이 중요하다

 

구현체는 memberRepository라는 인터페이스에 의존하고있고 동시에 MemberRepositoryImpl이라는 구현에도 의존하고있다

 

이렇게되면 DIP에 위배되는것이다 나중에 변경사항이 생기게되어 다른 로직으로 교체할때 추가로 코드를 수정해야하는 불편함이 생기게된다

 

이것을 해결하기위해서 나온것이 DI(의존성주입)인데 이것에 관해서 좀더 자세히 풀어볼까한다

외부에서 객체를 주입해주면 클라이언트 코드는 변경하지않고 외부에서 수정만해주면 되기떄문에

구현체에 의존하지않는다

 

그에따라서 인터페이스에만 의존하기때문에 DIP가 잘지켜지고 있다고 볼수있다 이제 한번 정리해보자

 

 

 

객체지향 5가지 원칙(SOLID)

SRP : 단일책임원칙

하나의 책임만 진다

 

OCP : 개방 폐쇠원칙

확장에는 열려있고 수정에는 닫혀있어야한다

 

LSP : 리스코프 치환원칙

하위타입은 상위타입으로 변경되어도 잘돌아가야한다

 

ISP : 인터페이스분리원칙

하나의 인터페이스보다는 좀더 세분화된 여러개의 인터페이스가 더좋다

 

DIP : 의존역전원칙

오로지 추상화나 인터페이스에만 의존해야한다