술(述)/풀이

ISP

쪼랩전사 2021. 12. 29. 22:44
728x90

정의

SOLID 중 I에 해당한다.

ISP는 Interface Segregation Principle의 약자로, 인터페이스 분리 원칙이다.

클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙이다. (인터페이스의 SRP)

 

ISP의 장점

  • 소프트웨어를 디커플링된 상태로 유지하게 해준다.
  • 리팩토링, 변경, 재배포를 더 쉽게 할 수 있게 해준다.

 

이 글을 쓰다가 문득, “그럼 인터페이스에 메소드를 하나씩만 넣으면 되지 않을까?” 생각했는데, 생각만 해도 끔찍하더라, 뭐든 적당한 게 좋다. 일단 코드 크기부터가 미칠 것 같다.

위반 사례

인터페이스가 클라이언트가 사용하지 않는 메소드를 가지는 경우 어떻게 될까?

아래 예시는 프린터가 스캔과 출력 메소드를 가지는 경우이다.

type Printer interface {
	Scan()
	Print()
}

type APrinter struct{}

func NewAPrinter() Printer {
	return &APrinter{}
}

func (A *APrinter) Scan() {
	log.Println("A가 스캔한다.")
}

func (A *APrinter) Print() {
	log.Println("A가 프린트한다.")
}

type BPrinter struct{}

func NewBPrinter() Printer {
	return &BPrinter{}
}

func (B *BPrinter) Scan() {
}

func (B *BPrinter) Print() {
	log.Println("B가 프린트한다.")
}

func main() {
	printer := NewAPrinter()
	printer.Scan()
	printer.Print()

	printer = NewBPrinter()
	printer.Scan()
	printer.Print()
}

이때, BPrinter가 ISP를 위반하는 경우이다. Scan 메소드에 내용이 없다. 솔직히 여기까지는 문제가 없다. 그냥 없으면 없는 대로 살아도 뭐...

 

문제는 Scan의 시그니처[각주:1]가 Read로 변경이 된다면 BPrinter도 같이 변경을 해줘야 한다. 귀찮다. BPrinter는 쓰지도 않는 메소드인데 귀찮지만 바꿔줘야 한다.

 

그걸 방지하기 위해서 나누면 아래와 같이 된다.

type Printer interface {
	Print()
}

type Scanner interface {
	Scan()
}

type AllInOnePrinter struct{}

func NewAllInOnePrinter() *AllInOnePrinter {
	return &AllInOnePrinter{}
}

func (A *AllInOnePrinter) Scan() {
	log.Println("AllInOne 가 스캔한다.")
}

func (A *AllInOnePrinter) Print() {
	log.Println("AllInOne 가 프린트한다.")
}

type OnlyPrinter struct{}

func NewOnlyPrinter() *OnlyPrinter {
	return &OnlyPrinter{}
}

func (o *OnlyPrinter) Print() {
	log.Println("Only 가 프린트한다.")
}

func main() {
	a := NewAllInOnePrinter()
	a.Scan()
	a.Print()

	o := NewOnlyPrinter()
	o.Print()
}

위 코드에서는 Scanner의 Scan 메소드의 이름을 변경하더라도 AllInOnePrinter 구현체만 영향을 받는다.

 

물론, 인터페이스는 만들었으면 안 바꾸는 게 제일 좋다. 하지만, 인터페이스가 처음부터 잘 만들어질 리가 없다.

마치며...

아무리 생각해도 인터페이스를 정의하는 것이 너무 어렵다. 그래서 요즘에는 초기 코딩할 때, 인터페이스에 대해서 생각 자체를 안 한다. 일단 만들고, 겹치는 부분이 생길 때가 되어서야 인터페이스를 정의하고 리팩토링을 시작한다. 일단 동작하는 거부터 만드는 것이 먼저다.


  1. 메소드 명과 입력, 출력 [본문으로]

'술(述) > 풀이' 카테고리의 다른 글

OCP  (0) 2022.01.04
SRP  (0) 2021.12.13
LSP  (0) 2021.12.10
bash 설정 파일  (0) 2021.12.05
code bloat(코드 비대화)  (0) 2021.11.24