본문 바로가기

python

python 객체지향 프로그래밍 SOLID 설계원칙

SOLID원칙이란?

Solid 원칙이란 로버트 마틴이 개발한 객체지향 프로그래밍 설계의 다섯가지 원칙을 말한다.


프로그램을 짜고 난 이후 오랜 시간이 지나서도 다시 유지보수 및 쉬운 확장을 하려고 할때


이 원칙들을 적용하면 작업을 무난하게 할 수 있다.


일단, SOLID의 원칙을 분리 해보면

Single responsibility principle (단일 책임 원칙)

모든 클래스는 단 한가지의 책임만 갖고, 클래스 안에 정의되어 있는 모든 기능은


이 하나의 책임을 수행하는데 집중되어 있어야 한다.


간단하게 하나의 클래스로 한가지만 일하자 이다.


응집도는 높게, 결합도는 낮게 설계하는것이 목표이다.


응집도 - 한프로그램의 요소가 얼마나 뭉쳐있는지, 즉 구성 요소들 사이의 응집력을 말하는것


결합도 - 프로그램 구성 요소들 사이가 얼마나 의존적인지를 말하는것


함수는 하나의 기능만을 수행하도록 구현 되야 하는것을 위 설명에서 말했다.


calculator라는 메서드가 덧셈, 뺄셈, 곱셈, 나눗셈을 모두 한다면 이는 좋은 설계가 아닌것이다.


각각의 메서드로 정의 되어 있어야 유지보수가 쉽고 좋은 설계라 할 수 있는것이다.


또다른 예시를 들어보면 Calculator 객체가 있고 덧셈, 뺄셈, 곱셈, 나눗셈이 각각 나누어져 있는 계산기 클래스에


알람 메서드를 Calculator의 기능으로 추가하는것은 단일 책임 원칙에 위배되는 행동이다.


한 객체에 책임이 많아 질 수록 클래스 내부에서 서로 다른 역할을 수행하는 코드끼리 강하게 결합될 가능성이 높아진다.


객체마다 책임을 제대로 나누지 않는다면 시스템은 매우 복잡해 질 것이다.


왜냐? 해당 객체가 하는 일(함수)에 변경사항이 생기면 이 기능을 사용하는 부분의 코드를 모두 다시 테스트해야 하기 때문이다.


그래서 여러 객체들이 하나의 책임만 갖도록 잘 분배한다면 시스템에 변화가 생기더라도 그 영향을 최소화 할 수 있기 때문에 SRP원칙을 따르는 것이 좋다.

Open/closed principle (개방-폐쇄 원칙)

위의 원칙을 보면 개방? 폐쇄? 라고 있는데, 여기서 개방과 폐쇄는 대체 뭘 뜻하는건지 궁금할 수 있다.


간단하게 말하면 클래스의 기존 코드를 변경하지 않으면서, 기능을 추가 할 수 있도록 설계 되는 원칙이라 말 할 수 있다.


다형성과 연관이 있을 수 있는데, 다형성을 가진 객체지향 프로그래밍을 하기 위해서 우리는 추상클래스를 이용했었다.


모듈들은 고정된 추상화에 의존하기 때문에 수정에 대해서 닫혀 있을 뿐만 아니라


추상클래스의 새 파생 클래스를 만드는 것을 통해서 확장이 가능하다.


추상화는 개방 폐쇄 원칙의 핵심 요소라고 할 수 있다.

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

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


부모 클래스의 인스턴스를 사용하는 위치에 자식 클래스의 인스턴스를 대신 사용했을때 코드가 원래 의도대로 동장하면된다.


애초에 자식 클래스의 인스턴스는 부모 클래스의 인스턴스이기 때문에 변수나 메서드를 상속 받으면 문제가 없지만,


만약 변수나 메서드를 잘못 오버라이딩한다면 문제가 생길 수 있다.


예시로 자식 클래스가 부모클래스 메서드의 파라미터 갯수, 리턴 타입, 부모클래스의 변수 타입을 바꾸면 문제가 발생할것이다.


또는 자식 클래스가 부모 클래스의 의도와는 다르게 메서드를 오버라이딩하는 경우도 생기는데, 이러한 부분들은 협업에서


아주 중요하게 여겨야 할 부분이다.


다시 간단하게 정리하면,


상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.

Interface segregation principle (인터페이스 분리 원칙)

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


인터페이스란 추상 메서드로만 이루어진 추상 클래스이다.


여러개의 인터페이스를 상속 받으면 다중 상속인데 다중 상속은 그렇게 추천하지 않는다고 알 고 있다.


좀 더 자세히 알아보면 인터페이스는 다중 상속의 경우, 반드시 필요한 추상 메서드들만


오버라이딩하여 클래스를 만들 수 있다.


인터페이스를 분리하지 않고 사용한다면 불필요한 메서드를 포함한 모듈이 만들어질 수 도 있으며


너무 많은 메서드를 포함한 뚱뚱한 인터페이스가 될 것이다.


그래서 인터페이스를 기능과 역할의 기준으로 나누고 필요한 인터페이스만 상속 받아 사용하는 것이 바람직한 프로그래밍 원칙이다.

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

상위 모듈은 하위 모듈의 구현 내용에 의존하면 안된다.


상위 모듈은 다른 클래스를 사용하는 주된 클래스 하위 모듈은 사용되는 클래스라고 생각하자.


예시로 게임 캐릭터가 있으면 이 캐릭터는 총을 무기로 사용한다.


그러면 여기서 총은 사용되는 인스턴스이기 때문에 하위 모듈 인스턴스이고,


캐릭터는 총이라는 인스턴스를 사용하는 상위 모듈 인스턴스라고 할 수 있다.


총 = 하위모듈 인스턴스 / 캐릭터 = 상위모듈 인스턴스