3월 27, 2022

SOLID 원칙

 객체지향 프로그래밍을 하며 지켜야 할 5가지의 원칙을 SOLID 원칙이라 합니다.

A. SRP(Single Responsibility Principle) - 단일 책임의 원칙 

클래스는 오직 하나의 기능만 가지며, 클래스의 모든 작업은 그 단일 책임에 종속돼야 합니다.

이에 맞추어  https://github.com/wecode-bootcamp-korea/30-2nd-WantU-backend/tree/main/applications 해당 링크의 applications view를 살펴보겠습니다.

우선 리팩토링 이전의 StatusView 코드입니다.


해당 view는 지원자의  지원 상태와, 그것들의 개수를 데이터베이스에서 가져오는 역할을 하고 있습니다.

34번째 줄에서 application.status.status는db에서 직접적으로 상태값을 가져오는 역할을 합니다. 

StatusView는 지원상태를 return 해줄 뿐 아니라, DB에서 직접 상태값들을 가져와 return할 값에 직접적으로 투입하고 있습니다. 

하나의 클래스가 여러 기능을 하고 있다고 보여지기에, enum클래스를 따로 만들어주어 상태값을 enum클래스를 통해 불러올 수 있도록 하겠습니다. 




enum 클래스를 분리해준 이후 , 이 클래스의 value값과 상태값의 id를 맞추어서 개수를 셀 때 Status 클래스를 사용해줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class StatusView(View):
    @login_decorator
    def get(self, request):
        applicant = Applicant.objects.filter(user=request.user).prefetch_related('application_set')
 
        if not applicant.exists():
            return JsonResponse({'result':"NO valid application"}, status = 404)
 
        applications_in_applicant = applicant[0].application_set.all().select_related('status')          
        status_list               = [application.status.id for application in applications_in_applicant]
 
        result = { 
            "applied"         : status_list.count(Status.APPLIED.value), 
            "document_passed" : status_list.count(Status.DOCUMENT_PASSED.value),
            "accepted"        : status_list.count(Status.ACCEPTED.value),
            "rejection"       : status_list.count(Status.REJECTION.value)
            }
 
        result["total"= len(status_list)
 
        return JsonResponse({'result':result}, status = 200
cs


B. OCP(Open Close Principle) - 개방폐쇄의 원칙

클래스는 확장에 대해서는 개방적이어야 하고, 변경에 대해서는 폐쇄적이어야 합니다.

클래스의 코드 변경은 이 클래스를 사용하는 모든 시스템에 영향을 미치게 됩니다. 따라서 클래스의 기능을 추가하려면, 기존 기능의 변경이 아닌 새로운 함수의 추가가 이상적입니다.


C. LSP(The Liskov Substitution Principle) - 리스코브 치환의 원칙

부모클래스 T의 서브타입인 자식 클래스 S의 객체는 어떠한 문제도 없이 부모 클래스의 객체를 대체할 수 있습니다.

문제없는 대체를 위해서, 자식 클래스는 부모클래스의 기능을 오버라이드 하지 않아야합니다. 자식 클래스는 부모의 기존 기능을 건드리지 않은 채, 확장만 수행하여야 LSP를 만족하게 됩니다

D. ISP(Interface Segregation Principle) - 인터페이스 분리의 원칙

바꿔 말하면, 인터페이스의 단일 책임 원칙입니다. 구체적인 책임을 지는 여러 인터페이스를 분리하여, 사용하지 않는 인터페이스가 존재하지 않게 해야 됩니다.


E. DIP(Dependency Inversion Principle) - 의존성 역전의 원칙

고차원의 모듈과 클래스는 저차원의 모듈과 클래스에 의존해서는 안됩니다. 고차원, 저차원 모두 구체에 의존적이지 않고, 추상에 의존해야 합니다. 구체는 추상에 의존적입니다.

고차원 모듈 또는 클래스는 저차원 모듈 또는 클래스를 도구로 하여 동작하는 클래스입니다. 추상은 두 클래스를 연결하는 인터페이스이고, 구체는 도구가 동작하는 방법입니다. 

자동차가 타이어를 사용할때, 한국타이어, 금호타이어등은 "구체"이고, 단순 "타이어"는 "추상"이라 할 수 있습니다. 자동차라는 고차원 클래스는 타이어라는 추상적 "인터페이스"에 의존하고 있습니다. 이때 타이어들은 모두 인터페이스 입니다.




출처 https://server-engineer.tistory.com/228

인터페이스를 통해 고수준 클래스가 저수준 클래스에 의존성을 가지지 않게 할 수 있습니다.

앞서 Enum클래스로 상태값을 분리해준 과정에서, StatusView는 고차원 클래스, Enum을 상속받은 Status는 저차원 클래스라고 생각됩니다.