1. 디자인 패턴에 앞서

디자인 패턴은 대학교에서 간단하게만 배웠던 기억이 닙니다. 대학원에서도 입사 준비 때도 주변에서는 디자인 패턴이 중요하다지만 실제로 잘 사용하는 사람은 없었고, 이게 왜 중요한지에 대해서도 체감하기 힘들었었습니다. 어렸을때는 내 코드에 대한 리뷰어나 배울만한 시니어 개발자들이 없었으니 당연하다 생각합니다. 제가 코딩과 공부를 능동적으로 안해온것이 크겠지만 패턴이 왜 쓰이는지 경험적으로 습득한것은 입사하고 나서부터 였으니까요.

디자인 패턴

디자인 패턴은 짧게 “객체지향 패러다임에서 더 좋은 코드란 무엇인가에 대한 고민의 결과” 입니다.

  • 중복의 최소화: 한 곳의 수정이 중복된 다른 코드에서의 수정을 동반해선 안됩니다
  • 코드 변경의 용이성: 코드는 항상 완벽하지 않고, 요구사항은 상시 바뀔 수 있습니다.
  • 재사용성: 정돈된 코드는 전혀 다른 요구사항 및 비슷한 경우에도 그대로 사용이 가능합니다.

너무나도 먼 디자인 패턴

우리는 어떻게보면 디자인 패턴을 모르는것이 당연합니다.

코드 한 줄의 변경이 다른 줄의 변경을 일으킬만한 큰 프로젝트를 만들어본적이 없습니다.

교내 팀 프로젝트에서 Web Application 으로 API 서버를 만들어서 고객 폰의 앱으로 주변 AP 정보를 파싱하고, LCD 패널이 붙은 라즈베리 파이로 해당 고객 위치에 따른 재실표시기를 만들었을때도 정말 코드가 단순명료했습니다. 학생분들이라면 아시죠 환경 계획 및 구축이 60% 고 개발이 20% 입니다. 남은 20% 은 술마셔야죠.

팀 프로젝트로 만든 코드는 다신 볼일이 없습니다.
요구사항 변경을 요청할 교수도 다른 프로젝트에 활용할 일도 없습니다.

팀 프로젝트 발표를 마치고 학점을 받으면 친척동생이 놀러와 롤을 깔때즘 용량문제로 소스코드를 지우는 상황에 이릅니다. 가끔 입사 준비 중 볼일이 있습니다만 예로 학부생 코드는 고쳐쓰는게 아니라했습니다.

결국엔 직접 해보아야 합니다.
본 카테고리에선 직접 해보며 조금이나마 짧고 명료하게 정리해놓으려합니다.
복습없인 항상 까먹기 일수거든요.

앞으로 본 카테고리에선 여러 디자인 패턴들에 대해서 살펴보려합니다. 각 패턴의 설명은 기본적으로 글을 사용하겠지만 클래스 다이어그램을 통해 이해를 도우려고 합니다.

클래스 다이어그램 화살표

클래스 다이어그램은 이름 자체가 내포하고있듯 Class 간의 관계를 표로 간단하게 설명한 것으로 Class 개념이 존재하는 객체지향 프로그래밍(OOP)에서 프로젝트 구현을 위한 설계도라고 보시면 될 것 같습니다. 클래스 다이어그램 자체로 한 챕터 분량이지만, 디자인 패턴에는 Class, Interface 이 둘만 필요하므로 딱 핵심적인 화살표 세 개만 살펴보겠습니다. 앞으로 Java 기반으로 설명하겠습니다.

implements (구현)

일반적으로 코드는 인터페이스를 단위로 구성됩니다. 사용하려는 구현 클래스를 코드 내에 지정하지 않고 인터페이스만을 명시하고 그 인터페이스의 위치에 원하는 구현 클래스를 연결(주입)하여 실제 작업을 수행합니다. 앞으로 설명할 모든 디자인 패턴의 주축이 되는 제 1 원칙이니 조금 더 설명드리겠습니다.

학생분들은 모든 클래스를 사용할때 아래 코드를 사용하실겁니다.

1
ConcreteClass class = new ConcreteClass();

우리가 배운 다형성을 활용하면 인터페이스와 구현 클래스를 나눠서 인터페이스에 우리가 원하는 구현 클래스들을 다음과 같이 동적으로 주입할 수 있습니다.

1
Interface class = new ConcreteClass();
1
Interface class = new SuperConcreteClass();

주입을 직접 Interface 에 하지않고 아래처럼 더 간편하게 함수를 통해 해줄 수 있습니다.

1
2
3
4
5
private Interface class;
public void setClass(Interface class) {
this.class = class;
}
setClass(new ConcreteClass();

사용하려는 구현 클래스가 무엇인지 바로 명시하지 않고 원하는 구현 클래스를 동적으로 Interface 에 외부에서 주입하기 때문에 결정권을 갖지 않는다는 이유로 Dependency Injection, 내지는 Inversion of Control 이라 부릅니다.

extends (상속)

상속은 클래스의 몇몇 함수에 대해 추가적인 기능이나 다른 로직의 함수로 대체하고 싶을때 사용합니다. 일반적으로 대학교때 객체지향 프로그램의 가장 큰 특성을 상속으로 배우고 Animal 과 같은 상위 클래스와 그를 상속하는 Cat, Dog 같은 하위 개념 클래스를 예제로 배우니 상위, 하위 클래스를 사용할때 상속을 많이 사용합니다. 하지만 상위, 하위 개념은 앞서 설명드린 implements(구현)에 해당합니다. 상위 개념을 Interface 로 두고 상위 개념에 해당하는 함수들을 하위 개념 Class 에서 명시하는것입니다.

반면 extends(상속)은 extends 가 의미하는대로 단순 확장에 해당합니다. Cat 중에서 줄무늬가 있는 Cat이 있을때 StripeCat 은 Cat 의 줄무늬를 제외한 모든 함수와 변수는 동일합니다.

composite (구성, 합성)

특정 클래스가 특정 클래스를 내부 변수로 갖고있는것을 뜻합니다. 구성은 단순히 갖고있다는 의미인데 왜 패턴에서 중요하게 쓰일까요. extend 가 interface 와 composite 의 조합으로 표현될 수 있기 때문입니다.

CatClass 가 줄무늬를 갖는것을 상속을 통해 Sprite 함수 및 변수를 넣어주지 않고, “종” 이라는 하나의 상위 클래스를 두고 “줄무늬종” 임을 하위 클래스로 명시해준다면 상위 개념인 “종”에 그 하위에 무슨 “종”이든 다 넣을 수 있는 확장성을 갖게됩니다. 바로 위 extends(상속)과 비교해보십시오. 좌측에 SpriteCatClass 가 갖고있던 Sprite 정보가 우측 클래스로 이동했습니다. Inversion of Control 의 의미가 조금 짐작되시는지요.

CatClass 가 줄무늬뿐만 아니라 두 눈이 오드아이라고 설정해봅시다. 이 또한 상위-하위 개념인 interface 와 has 를 통해 EyesClass 에 OddEyesClass 를 명시하는것이 좋겠지요. 아까 제 1 원칙 “구현이 아닌 인터페이스에 맞춰 프로그래밍 한다.” 다음에 제 2 원칙 “상속대신 구성과 인터페이스를 사용한다” 가 되겠습니다.

이제 이 세 개의 화살표(구현, 상속, 구성)와 두 개의 원칙으로 디자인 패턴들을 살펴보겠습니다.


1: https://martinfowler.com/articles/injection.html
2: http://www.nextree.co.kr/p11247/
3: http://www.nextree.co.kr/p6753/

Author

Aaron Ryu

Posted on

2018-12-30

Updated on

2019-02-23

Licensed under

Comments