[TIL] SOLID : 유지 보수와 확장이 쉬운 애플리케이션을 만들자.

Doodung·2022년 1월 11일
0

Design Pattern

목록 보기
2/4
post-thumbnail

절차에서 객체로 생각하기

  1. 객체지향 : 실세계를 직접적이고 직관적으로 모델링 할 수 있는 패러다임
  2. 순수함수 : 입력 그대로 나오는 것 → 순수 함수는 object class로 만들어주는 것이 좋다
  3. 커피 이름, 칼로리, 가격이 들어가는 data class가 생각나는 형태는 enum class로 만들자

SOLID 원칙

코드의 가독성을 높이고 확장이 쉬운 구조를 만들자.

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

모든 클래스는 각각 하나의 책임만 져야한다. 클래스는 그 책임을 완전히 캡슐화 해야한다.
클래스가 제공하는 모든 기능은 이 책임과 주의 깊게 부합해야 한다.

단일 책임 : 어떤 클래스나 모듈 또는 메서드가 단 하나의 기능을 가져야 한다.
즉 변경 사항이 발생하더라도 그 변경 사항에 대한 책임이 있는 부분만 수정하면 된다.

ex) 특정 데이터를 분석하고 서버에 전송하는 모듈
이 모듈은 두가지 이유로 변경될 수 있다.
1. 데이터를 분석하는 알고리즘 때문에 변경될 수 있다.
2. 서버에 전송하는 형식 때문에 변경될 수 있다.
단일 책임 원칙에 의하면 이 문제의 두 측면이 실제로 분리된 두 책임 때문이며, 따라서 분리된 클래스나 모듈로 나누어야 한다.
다른 시기에 다른 이유로 변경되어야 하는 두가지를 묶는 것은 나쁜 설계일 수 있다.

why?
한 클래스를 한 관심사에 집중하도록 유지하는 것이 중요한 이유는 이것이 클래스를 더욱 튼튼하게하기 때문이다.


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

소프트웨어가 확장에 대해서는 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다는 원칙이다.

기존의 코드를 밝히지 않으면서, 기능을 추가할 수 있도록 설계 되어야 한다.

어떠한 내용을 수정하기 위해 연관된 다른 코드나 모듈까지 수정하는 것은 어렵고 난감하다. 개방-폐쇄 원칙은 시스템의 구조를 올바르게 구성하여 변경 사항이 발생하더라도 다른 코드나 모듈에 영향이 없도록 하는 것이다.
개방-폐쇄 원칙이 잘 적용된 경우, 새로운 기능을 추가하거나 기존 기능을 변경하기가 용이해진다.

개방-폐쇄 원칙은 객체 지향 프로그래밍의 핵심 원칙이라고 할 수 있다. 개방-폐쇄 원칙을 따르지 않는다고 해서 객체 지향 언어 구현이 불가능한 것은 아니지만, 이 원칙을 무시하고 프로그래밍을 한다면 객체 지향 프로그래밍의 가장 큰 장점인 유연성, 재사용성, 유지 보수성 등을 결코 얻을 수 없다. 따라서 객체 지향 프로그래밍 언어에서 개방-폐쇄 원칙은 반드시 지켜야 할 기본적인 원칙이다.

상속관계를 명확하게 해야한다. -> 인터페이스를 만들자~!! 밖에서. (생성자에서)


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

치환성은 객체 지향 프로그래밍 원칙이다. 클래스 S가 클래스 T의 자식 클래스라면 별다른 변경 없이 부모 클래스 T를 자식 클래스 S로 치환할 수 있어야 한다는 원칙이다. 즉 다운 캐스팅된 인스턴스가 논리적으로 그 역할이 문제 없어야 한다.

리스코프의 원칙은 객체 지향 프로그래밍 특징에 관한 몇 가지 표준적인 요구 사항을 강제한다.

  • 하위 클래스에서 메서드 파라미터의 반공병성
  • 하위 클래스에서 반환형의 공변성
  • 하위 클래스에서 메서드는 상위 클래스 메서드에서 던져진 예외 사항을 제외하고 새로운 예외 사항을 던지면 안됨
  • 하위 클래스에서 선행 조건은 강화될 수 없음
  • 하위 클래스에서 후행 조건은 약화할 수 없음
  • 하위형에서 상위형의 불변 조건은 반드시 유지되어야 함.

다음과 같이 차례로 상속받는 타입이 있다고 가정한다. A<-B<-C

public class A{}
public class B extends A{}
public class C extends B{}

공변성의 예를 들면, List<?extends B>란 B를 상속받는 타입으로 이루어진 리스트가 있다면 List를 사용할 수 있다는 내용이다. 반공변성의 예를 들면, List<?extends B>란 리스트가 있을 때 List<A>를 사용할 수 있다는 것이다. 물론 A의 부모 타입으로도 치환이 가능하다.

불변성은 위의 공변성과 반공변성을 허용하지 않는 경우이다.


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

인터페이스 분리 원칙은 어떠한 클래스가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙이다.

인터페이스 분리 원칙은 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리함으로써 클래스들이 꼭 필요한 메서드들만 이용할 수 있게 한다. 이와 같은 작은 단위들을 역할 인터페이스라고도 부른다. 인터페이스 분리 원칙을 통해 시스템의 내부 의존성을 약화해 리팩토링, 수정, 재배포를 쉽게 할 수 있다. 큰 덩어리의 인터페이스를 구체적이고 명확한 단위로 나누어야 한다.

인터페이스 분리 원칙 ex) 독수리를 클래스로

public abstract class Bird{
	abstract void fly();
	abstract void cry();
}
public class Eagle extends Bird{
	@Override
	public void fly(){...}

	@Override
	public void cry(){...}
}

Bird라는 추상 클래스를 만들어서 새의 울음소리를 내고 날 수 있는 기능을 가진 메서드를 만든 뒤 Bird를 상속받은 Eagle을 만들었다. 이때 Penguin 클래스를 만든다면 펭귄은 새지만 날지는 못하므로 fly() 메서드를 가지면 ISP 인터페이스 분리 원칙에 어긋날 수 있다. 다음과 같이 코드를 수정할 수 있다.

public abstract class Bird{
	abstract void cry();
}
public interface Flyable{
	void fly();
}
public abstract class FlyableBird extends Bird implements Flyable{...}
public class Eagle extends FlyableBird{
	@Override
	public void fly(){...}

	@Override
	public void cry(){...}
}
public class Penguin extends Bird{
	@Override
	void cry(){...}
}

fly() 메서드를 인터페이스로 분리하고 날 수 있는 새에만 구현함으로써 펭귄은 사용하지 않는 fly() 메서드를 가지지 않을 수 있어 ISP 원칙을 지킬 수 있게 되었다. 펭귄에게 swim() 메서드를 추가하고 싶다면 Swimmable 인터페이스를 만들어 볼 수도 있다.


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

고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다. 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.

객체 지향 프로그래밍에서 의존 역전 원칙은 모듈들을 분리하는 특정 형식을 지칭한다. 이 원칙을 따르면, 상위 계층이 하위 계층에 의존하는 전통적인 의존 관계를 역전시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있다.

  1. 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.
  2. 추상화는 세부사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.

이 원칙은 '상의와 하위 객체 모두가 동일한 추상화에 의존해야 한다'.는 객체 지향적 설계의 대원칙을 제공한다.

EX) 어떤 기기가 단 한가지 종류의 전용 충전기에만 충전되고, 다른 충전기는 호환되지 않는다면 이 기기는 전용 충전기에 강한 의존성을 가진다고 말할 수 있다.
전용 충전기가 필요 없이 같은 타입단자라면 어느 제조사의 것도 맞는다고 하면 이것은 충전기에 대한 약한 의존성을 가진다고 말할 수 있다.
이때 이런 USB-C타입 이라는 계층을 인터페이스라고 한다. 이렇게 충전기의 단자를 추상화 시켜서 기기가 특정 충전기에 의존하던 것을 인터페이스를 통해 의존성을 역전시켰다. 따라서 이제 제조사의 충전기가 C타입이라는 인터페이스에 의존하게 된것이다.



출처 - 아키텍처를 알아야 앱개발이 보인다 / 옥수환

profile
반가워요!

0개의 댓글