객체지향 디자인패턴 13종

KIM YONG GU·2023년 9월 23일

얄팍한코딩사전

목록 보기
23/23

객체지향 언어로 프로젝트를 진행할 때 익혀두면 유용할 패턴들.
영상에서 12가지를 패턴들을 알아보겠습니다.

1. Singleton 패턴 (싱글톤 패턴)

간단하지만 중요하고 유용한 패턴.
어떤 페이지에서 다크모드를 유지한다고 가정.
static은 이미 메모리의 정적공간에 자리를 차지하고 있는 상태이기 때문에 해당 객체의 new를 생성할 필요없이 클래스에서 바로 변수를 사용할 수 있다.
(이미 크기가 정해져있기 때문)

Q. 왜 정적변수들을 쓰지 싱글톤을 쓸까?
interface의 사용하는 lazy loading 싱클턴으로 할 수 있는 것들이 더 많기 때문이에요.

그러나 이렇게만 작성하면 멀티스레드 등의 환경에서 오류가 발생할 소지들이 있다.
그래서 싱클턴을 더 안전하게 사용할 수 있는 방법들을 언어마다 검색해보시면
좋은 자료들을 찾으실 수 있을거에요

2. Strategy 패턴 (전략 패턴)

프로그램 실행중 모드가 바뀔 때마다 검색이 이뤄지는 방식, 즉 전략이 수정된다는 거죠.

전략 패턴은 모드마다의 동작 하나하나를 모듈로 따로 분리해서, 이 버튼들을 누를때마다
이 검색버트늘 누를때 실행될 검색 모듈을 갈아끼워주는 방식으로 코드를 짜는 것

인터페이스는 그 자체로는 객체를 만들 수 없지만, 특정 인터페이스를 implement한 클래스는
해당 인터페이스에서 지정한 메소드를 필수적으로 선언해서 장착해야 해요.

예를들어 영상 검색이라는 새 방식이 추가되면 SearchStrategy를 implement한 새 클래스를 만들면 된다. 이처럼 옵션들마다 행동의 모듈화해서 독립적이고 상호 교체 가능하게 만드는 것이 stratety 패턴이다.

3. State 패턴

strategy 패턴과 비슷한 면이 있음.
strategy 패턴은 어떤 동일한 틀 안에 있는 특정 작업의 방식, 모드를 바꿔줄 때.
state 패턴은 TV가 꺼져 있을 때 누르면 켜지고 켜진 상태에서 다시 누르면 꺼지는 버튼처럼
특정 상태마다 다르게 할 일을 나아가서 그 상태들 자체를 그 상태마다 실행시 할일과 함께
하나하나 모듈화해서 지정해 둘 때 쓰이는 거죠.

=> 각각의 메소드 끝단에서 서로 반대되는 메소드를 호출하도록 되어있다.
물론 이는 하나의 예시이며 선택분기에 따라 다른 메소드를 호출하도록 할 수도 있다.

strategy가 모듈화된 모드에 따라 다르게 실행되도록 하는거라면
이 state 패턴은, 그 메소드가 실행될 때 모드도 전환되도록 하는 것이라고 이해하셔도 좋아요

4. Command 패턴

strategy 패턴과 매우 유사한 면이 있음.
근본적인 차이는, 전략 패턴은 같은 일을 하되 그 알고리즘이 방식이 갈아끼워지는 것이라면
커맨드 패턴은 그 하는 일 자체가 다른거라고 생각하시면 문제없을거에요
떄문에 커맨드 패턴이 사용되는 모습은 보다 다양해요.

전략패턴의 예제처럼, 모드 변경에 따라 명령을 갈아끼워넣는 식으로 진행되기도 하고
위키피디아의 예시처럼 스위치를 ON/OFF 할 때마다 다른 명령어를 실행시킬 수도 있다.

일반적으로 command 예제에서는 interface를 사용하지만 여기에서는 absract를 사용해보기로 해요.

커맨드 툴을 잘 이용하면 각종 생산성 툴처럼, 여러 작업을 수행한 뒤
뒤로가기나 앞으로가기를 구현하는 등 다양한 방식으로 활용될 수 있을 거에요.

말 그대로 연속적인 명령어의 나열?을 구현할 때 좋은듯?

5. Adapter 패턴

객체지형 프로그램에서 어댑터는 보통 인터페이스가 서로 다른 객체들이 같은 형식 아래서 작동할 수 있도록 하는 역활을 함.

양식 식당에서 요리사에게 요리하세요. 디저트를 제공하기 위한 제과사에게 디저트 준비해주세요.
라고 하기에는 복잡하니 어답터를 달아서 요리해주세요 하면, 알아서 디저트를 준비해주는 역활.

예를 들어 다른 서비스의 인터페이스는 우리 인터페이스와 다르다.
이걸 다 수정하는 것은 매우 비효율적인 일.
따라서 같은 버튼을 누르면 같은 일을 수행할수 있도록 중간에 변환해주는 것(adapter)을 넣는다.

6. Proxy 패턴

회사 대표는 바빠서 비서, 대리인을 통해 일을 해결하기도 한다.
프로그래밍에서 사용되는 클래스 중에서도 인터넷에서 받아와야 해서 시간이 걸리거나 메모리를 많이 차지하거나 하는 등의 이유로 객체로 여럿 생성하기가 부담이 되는 것들이 있다.

그럴 때는 그 클래스의 'proxy', 대리인의 역활을 하는 클래스를 따로 두어서,
가벼운 일은 그 비서가 처리하고 대표가 직접 나와야 할 수 있는 무거운 작업을 해야 할 때
비로소 실제 클래스를 생산해서 사용하는거에요.

제목은 프록시 클래스가 처리하고, 프리뷰 보여주기는 무거운 작업이므로 실제 클래스가 처리하게 작성한다.

7. Facade 패턴

여러 클래스의 객체들을 복합적으로 사용해야 수행할 수 있는 작업들이 있죠
예전에 구글 및 카카오 지도 API 서비스 제공할 때 했던 비슷한 작업?

8. Template-method 패턴

템플릿 메소드 패턴이란 어떤 같은 형식을 지닌 특정 작업들의 세부 방식을 다양화하고자 할 때

전략패턴의 경우는 모듈화된 형식으로 따로 만들었었음.

템플릿 메소드 패턴은 이와는 달리 다양화된 각각 자식 클래스에서 오버라이딩 하는 방식으로 구현되는 거에요.

그러면 객체지향의 단순한 상속일 뿐인데 왜 패턴으로 따로 구분한 것일까요?
템플릿 메소드의 상식에는 일정한 형식이 있다. 부모 클래스에 전반 과정을 수행하는 메인 메소드가 있고 그 과정 가운데 세부 메소드가 있다.

메인 메소드를 실행하면 실행중에 이 세부 메소드들이 호출되는 형태죠
자식 과정에서는 그 세부 메소드를 오버라이딩 하는거에요

전체 과정은 부모 클래스에서 유지하되.
세부 과정은 자식 클래스에서 특색있게 구분해서 구현한다.

카카오지도 API와 네이버지도 API의 각 기능의 작동방식은 다르지만
서버에 연결하고, 맵을 띄우고, 현재 위치로 이동한다는 전체적인 틀은 같다.

템플릿 메서드 패턴은 어떤 일을 수행하는 몇 가지 방법이 있는데, 그 전반적 과정에 공통된 절차가 있을 때 코드를 효율적으으로 짜기 위해 만들어진 패턴이다.

9. Decorator 패턴

특정 클래스의 객체들이 할 수 있는 일을 여러가지 두고 각 개체마다 사용자가 원하는대로 골라 시키거나 기능들을 필요에 따라 장착할 수 있도록 할 때 데코레이션 패턴이 사용된다.

객체가 생성자 변수로 다른 객체 안에 들어감으로써 그 실행하는 메소드의 행동이 추가되도록 한 것이 데코레이터 패턴이다.

10. Factory-method 패턴

팩토리-메소드 패턴을 이용하면 이처럼 어던 다른 클래스, Factory 안에서
주어진 조건에 따라 적절한 것을 생성해서 반환값으로 나오는 객체를 값으로 넣어주게돼요.

실전 코딩 경험이 많지 않은 분들은 의아할거에요.
아니 다른 패턴들은 써서 뭐가 편해지는지 알겠는데. 이건 왜 이렇게 하는거지?

팩토리 패턴은 크게 두 가지 효용을 가져요.

첫번째.
이 객체들을 생성하는 코드는 여러 곳에 있을 수 있죠.
그런데 만약 이 생성자가 변경되거나 하면 이 코드들 하나하나를 찾아서
새 생성자 형식에 맞게 코드들을 변경해줘야겠죠.

객체들을 생성하는 코드들이 많으면 많을수록
객체의 생성자를 변경하거나, 사용되는 객체 자체를 변경하는데 있어 부담이 커질거에요
이 역할을 이 팩토리 클래스가 대신하도록 하면
이제 이 메소드 내부만 변경시키면 되겠죠.

두번째.
조건에 따라 객체를 생성해 가져오는 일을 이 팩토리 클래스에 위임해버림으로서
이 부분을 짜는 개발자들로 하여금 이 클래스들에 대해 알 필요가 없도록 하는거에요

모든 걸 직접 만들어서 프로그래밍하는 경우는 드물죠
안드로이드나 스프링 등 이미 현존하는 프레임워크 위에서
기존에 만들어진 라이브러리, 클래스들을 활용해요

특정 종류의 기능들에 사용될 수 있는 클래스들의 종류가 많고 복잡할 때
이를 사용하는 개발자 측에서는 이들을 다 알 필요 없이
약국에서 약사에게 증상을 얘기해줄때처럼 클릭할 거, 온오프 토글할거, 펼쳐서 고를거
이렇게 사용할 객체들의 조건들만 인자로 넘겨주면
이에 적절한 클래스를 찾아 객체로 생성해 넘겨주는 일은
팩토리가 알아서 처리하는거죠.

그리고 단순히 클래스를 골라주는 것 뿐이 아니에요
아까 데코레이터 패턴(전투기)에 팩토리 패턴을 적용해볼게요

내가 쓸 때는 상관없지만 남에게 넘겨줄때는 보다 간단히 사용할 수 있도록 해주는게 좋겠죠?

전투기 공장을 만들어봅시다.

...이 메소드의 세 인자들에 값을 어떻게 주느냐에 따라 필요한 데코레이터로만 덧입혀진 결과물을 받을수 있겠죠. 이 간단한 팩토리 클래스로 필요에 따라 8가지 조합의 결과물을 받을 수 있는 거에요.

11. Abstract-factory-method 패턴

추상 팩토리 메소드 패턴은 이 팩토리 메소드 패턴에 한 단계 더 추상화가 입혀진 패턴이라고 보시면 되요.
특정 객체들을 찍어낼 공장, 팩토리도 여러 종류로 건설할 수 있도록 하는거죠.

12. Mediator 패턴

중재자 패턴.

어떤 클래스의 객체에서 특정 이벤트가 발생할 때마다 연결된 다른 클래스들에 알려야 하는 경우가 있어요. 리스트 또는 갤러리 모드를 토글하면 리스트 뷰와 갤러리 뷰 중 하나는 보이고 하나는 감추고 데이터를 받아오는 객채에는 새 모드에 맞게 다운로드 명령을 다시 내려줘야겠죠

이를 패턴 없이 코드로 짜 보면 ...(중략)... 그리고 이처럼 모드를 다른 것으로 바꿀 때마다 이것들에 하나하나 모드 변경에 따르는 함수를 호출하는 코드를 일일이 작성해줘야 하는 거에요.
만약 앱에 기능과 요소들이 추가되면서 모드에 영향을 받는 클래스들이 늘어난다면 그 코드들을 계속해서 이 모드스위치 클래스에 하나하나 추가를 해줘야겠죠. 중간에 이것들이 동적으로 추가되는 제거되는 기능도 이런 형태로는 작성하기가 꽤나 번거로울 거에요.

미디에이터 패턴은 이처럼 특정 이벤트에 반응해서 관련된 다른 클래스들에 알려주는 역활 mediator, 중재자 역할을 하는 클래스에 전담시키는거에요. 거래처에 전화를 돌릴 외주업체를 따로 두는거죠.

우측의 클래스들이 공통적으로 모드에 반응하는 ModeListener 인터페이스를 장착하도록 해요.
셋 모두 ModeListenr 타입으로 인식될 수 있겠죠. 이제 연락담당인 ModeMediator 클래스를 만들어요. ...(중략)...

여러 클래스들의 관계가 특정 이벤트들을 중심으로 복잡하게 얽힌 설계에서 유용하게 사용될 수 있겠죠.

13. Composite 패턴

컴포지트 패턴을 쉽게 이해하려면 컴퓨터의 폴더 시스템을 떠올리시면 되요, 폴더 안에는 파일들도 들어갈 수 있지만 또 다른 폴더들도 들어갈 수 있고, 해당 폴더도 다른 폴더 안에 포함될 수 있죠.

폴더와 파일은 엄연히 다른 종류지만 둘다 이름 바꾸기, 용량 구하기, 삭제하기 등의 명령을 받을 수 있구요. 이처럼 포함되는 것들과 포함된 것들이 같은 방식으로 다뤄질수 있도록 할 때 컴포지트 패턴이 사용되요.

...자료구조에서 배웠던, 트리를 탐색할 때 처럼 내부 가지들을 다 돌면서 용량을 구한 뒤 전체 용량을 반환하는 것을 볼 수 있죠. 폴더를 삭제하는 과정이 똑같이 이뤄져요. 이걸 발전시켜서, 내부 파일을 검색하거나 하는 등 다양한 기능들을 구현할 수 있곗죠. 이런 간단한 코드들로 이런 시스템을 구현할 수 있다는게 정말 GIT똥차지 않나요?

맺으며

단진 패턴들의 설계구조만 머릿속으로 외우는게 아니라 그것들이 왜 만들어졌는지, 어떻게 활용이 가능하고 다른 패턴들과는 또 어떻게 어우러질 수 있는지 고민한다면 굳이 어떤 패턴을 사용한다는 의식 없이도 객체지향의 가능성을 최대한 활용하는 멋진 코드를 작성하실 수 있을거에요.

profile
Engineer, Look Beyond the Code.

0개의 댓글