1. 디자인 패턴 어떤거고? 왜 배워야 될까?
💡 객체지향 설계를 처음하는 개발자와 객체지향 설계에 익숙한 사람의 차이점은 무엇인가?
위에 질문에 대한 아래와 같은 답변을 들은 기억이 있습니다.
객체지향 설계를 처음하는 개발자는 모든 문제를 기초 단계에서 해결하려고 하고
객체지향 설계에 익숙한 개발자는 문제가 생기더라도 예전에 사용했던 해결법을 다시 사용하려고 응용한다!
⇒ 그리고 이 내용을 토대로 프로젝트에서 반복적으로 발생하는 다양한 문제의 해결법을 구조화시킨 것이 디자인 패턴입니다!
제 개인적인 해석으로는 디자인 패턴은!
객체지향 설계 즉. SOLID에 맞춰서 결합도를 낮추고 응집도를 높이는 개발을 고민하는 과정 속 발생되는 반복적인 문제들의 해결법을 간단히 정리한것이라고 생각합니다!
그럼 어떤 장점이 있을까?
- 재사용이 가능한 설계를 선택할 수 있는 관점
- 재사용을 방해하는 설계는 피할 수 있는 관점
- 이미 만들어진 시스템의 유지보수 or 객체 간의 상호작용 또는 설계의 의도를 명확히 정의 가능
전 여기서 가장 핵심을 관점과 정의로 생각했는데요! 개발을 하면서 제가 계속 하려고 노력하는 것이 '아는만큼 보인다' 와 '보인것을 말로 잘 설명할 수 있어야 한다!'이기 때문에 디자인패턴이 굉장히 중요하다고 생각합니다!
2. 디자인 패턴 분류하기
총 23가지 패턴이 존재하고 각각의 기준에 따라 분류할 수 있습니다
i) 목적
패턴은 생성, 구조, 행동 중 한가지 목적을 갖습니다
생성: 객체의 생성 과정에 참여하는 것.
→ 객체의 생성과 조합을 캡슐화해 특정 객체가 생성되거나 변경되어도 프로그램 구조에 영향을 크게 받지 않도록 유연성을 제공구조: 클래스나 객체의 합성에 관한 것.
→ 서로 다른 인터페이스를 지닌 2개의 객체를 묶어 단일 인터페이스 제공 or 객체들을 서로 묶어 새로운 기능을 제공하는 것행동: 클래스나 객체들이 상호작용 하는 방법과 책임을 분산하는 방법에 관한 것.
→ 한 객체가 혼자 수행할 수 없는 작업을 여러 개의 객체로 어떻게 분배하는지, 또 그렇게 하면서도 객체 사이의 결합도를 최소화하는 것에 중점!
ii) 범위
패턴을 주로 클래스에 적용하는지, 객체에 적용하는 지 구분!
- 생성
- 클래스: 객체를 생성하는 책임의 일부를 서브 클래스가 담당
- 개게: 객체를 생성하는 책임의 일부를 다른 객체가 위임
- 구조
- 클래스: 상속을 이용해 클래스 복합
- 객체: 객체 합성
- 행동
- 클래스: 상속을 이용해, 알고리즘과 제어 흐름 기술
- 객체: 하나의 작업을 수행하기 위해 객체 집합이 어떻게 협력하는지 기술
3. 디자인 패턴을 통해 문제를 해결하는 방법
우리는 디자인 패턴을 통해 결국 객체지향 프로그래밍 중 발생하는 반복적 문제를 해소하려고 한다. 그러기 위해선 가장 먼저 “객체”에 대한 명확한 이해가 필요하다.
3-1. 객체 지향 프로그램에서의 “객체”
객체는 데이터와 데이터에 연산을 가하는 프로시저를 함께 묶은 단위
- 요청: 객체가 연산을 실행하게 하는 유일한 방법
- 연산: 객체 내부 데이터의 상태를 변경하는 유일한 방법
⇒ 요청을 던진 객체 외부에서 내부 데이터에 직접 접근 x (오직 요청) 이러한 상태 캡슐화!

3-2. 그럼 객체지향 프로그램은?
위에서 설명한 객체끼리 “협력”하여 각자의 “역할”을 수행하는 식
⇒ 그렇기에 객체의 분할이 이루어져야 하고 다양한 요인을 고려해서 처리해야 되기 때문에 굉장히 어려운 부분입니다
그리고 우리는 앞으로 나올 디자인 패턴을 통해 어떤 관점으로 객체를 분할하고 다뤄야 할지 공부를 할겁니다!
4. 객체 인터페이스 명세
4-1. 시그니처와 인터페이스
객체가 선언하는 모든 연산은
- 연산의 이름
- 매개변수로 받아들이는 객체
- 연산의 반환값
을 명세해야 하고 이를 연산의 “시그니처”라고 부르게 됩니다!
그리고 인터페이스는 객체가 정의하는 모든 시그니처를 일컫는 말!
→ swift에서는 인터페이스를 프로토콜을 이용해 구현하며, 프로토콜 안에 메서드가 시그니처 개념이 됩니다!

4-2. 외부에서 객체를 알 수 있는 방법은 only 인터페이스!
아까 위에서 객체를 설명했을 때 오직 요청과 연산만이 객체에 접근할 수 있는 유일한방법이라 설명했고
⇒ 다시 말해 인터페이스를 통해서만 처리를 요청할 수 있고, 객체의 인터페이스는 어떻게 구현하는지 직접 알 수가 없습니다. (캡슐화 때문!)
따라서 항상 실제 구현부와 인터페이스를 나누는 것이 굉장히 중요합니다!
그리고 이것이 객체 지향에서 가장 기본적인 개념이 된다. 객체는 즉 인터페이스로 자신을 드러내게 됨!
💡 실제 구현부를 나누는 것은 객체지향적인 관점에서 단일 책임 원칙, 모듈화, 의존성 관리, 재사용성, 확장성, 테스트 용이성, 유지보수성 등을 보장하고 코드의 구조를 개선하는 방법입니다. 이를 통해 더 효율적이고 관리 가능한 소프트웨어를 개발할 수 있습니다.
4-3. 동적 바인딩 & 다형성
이러한 요청과 그 요청을 처리할 객체를 프로그램 실행 중에 즉 런타임에 이 둘을 연결 시키는 것.
동적 바인딩은 프로그램이 기대하는 객체를 동일한 인터페이스을 갖고 잇는 객체로 얼마든지 갈아 끼우는게 가능하다는 의미를 가집니다.
이러한 대체성을 우리는 “다형성” ⇒ 객체간의 결합도를 없애며, 서로 간의 관련성을 다양화 시켜줌!
5. 객체 구현 명세하기
💡 객체의 구현 → 클래스를 정의하는 과정
클래스는 객체 내부 데이터와 표현 방법을 명세하고, 수행할 연산도 같이 정의 이를 시각적으로 표현하기 위해 OMT 기반 표기법을 사용합니다!

이러한 클래스도 두가지로 나뉘게 되는데
- 추상 클래스: 모든 서브 클래스 사이에 공통되는 인터페이스 정의 ⇒ 인스턴스 생성 x (프로토콜)
- 구체 클래스: 추상 클래스가 아닌 클래스 ⇒ 인스턴스 생성 0

추상 클래스는 점선, 상속은 삼각형 (삼각형 꼭지점 위: 슈퍼클래스, 아래가 서브 클래스)
6. 객체 지향 행동 복합
총 3가지가 있습니다
상속: 서브 클래스에 의해 연산 구현
상속에서도 2가지로 나뉘게 되는데요
- 클래스 상속: 객체 구현을 정의할 때, 이미 정의된 객체의 구현을 바탕으로 코드와 내부 표현구조 공유
- 이미 다 갖춰진 연산과 데이터를 받아서 처리
- 새로운 구현에 드는 비용이 적은 편 (부모 클래스꺼 쓰면됨)
but 구현을 물려받아도 재사용이 완벽함? x
- 인터페이스 상속: 연산의 정의만 물려받게 되는 형식 → 어떤 객체가 다른 객체 대신에 사용될 수 잇는 경우 지정할 수 있다!
- 사용자들은 그 객체가 인터페이스를 만족하면 → 객체 타입은 알빠 아님
- 사용자들을 클래스를 알 필요 없고 → 프로토콜에게만 시키면 됨
⇒ 시스템 간 종속성이 없어짐!
합성: 다른 객체를 여러 개 붙여서 새로운 기능 혹은 객체 구성
중복되는 로직들을 갖는 객체를 구현하고, 이 객체를 주입받아 중복 로직을 호출함으로써 퍼블릭 인터페이스를 재사용하는 방법
장점
- 객체의 내부는 공개되지 않고, 인터페이스를 통해 코드를 재사용
⇒ 구현에 대한 의존성을 인터페이스에 대한 의존성으로 변경하여 결합도를 낮춤!
결론: 상속보단 합성! (클래스는 서브클래스가 부모클래스 구현에 종속될 수 밖에 없음..)
- 캡슐화가 깨지고 결합도가 높아짐
- 유연성 및 확장성이 떨어짐
- 다중상속에 의한 문제가 발생할 수 있음
- 클래스 폭팔 문제가 발생할 수 있음
매개변수화: 타입을 정의할 때 타입이 사용하는 모든 타입을 지정하지 않은 채 정의
기능의 재사용에 이용할 수 있도록 도움 ⇒ 대표적인게 Generic!
객체 생성 시 타입을 명시하지 않고 나중에 지정하도록 해서~ 유연해짐~
한줄 정리
- 디자인 패턴은 객체지향 설계 즉. SOLID에 맞춰서 결합도를 낮추고 응집도를 높이는 개발을 고민하는 과정 속 발생되는 반복적인 문제들의 해결법을 간단히 정리한것!
- 그럼 객체는 무엇일까? 객체는
- 데이터와 데이터에 연산을 가하는 프로시저를 함께 묶은 단위
- 외부에서 객체에게 할 수 있는 것은 only 요청 즉, 내부 데이터 직접 접근을 못하도록 캡슐화 해야된다! 그리고 이 요청에 따라 객체 내부 데이터의 상태를 변경하는 연산을 할 수 있다.
- 객체는 캡슐화 되어야하므로 우리는 실제 구현부와 인터페이스를 나눠서 객체가 인터페이스를 통해 자신을 드러낼 수 있도록 해야한다!
- 그럼 왜 직접 접근하면 안되나? 결합도가 높아지고 캡슐화가 깨짐 → 객체지향 프로그래밍에 어긋남!
- 그렇기에 강한 결합도와 캡슐화를 깨는 상속보다는 객체를 합성하는 것이 좋은 프로그래밍이다!
[참고자료]
[OOP] 코드의 재사용, 상속(Inheritance)보다 합성(Composition)을 사용해야 하는 이유
[OOP] 코드의 재사용, 상속(Inheritance)보다 합성(Composition)을 사용해야 하는 이유
객체지향 프로그래밍에서 코드를 재사용하기 위한 방법으로 크게 상속과 합성이 있습니다. 대부분의 경우 상속보다 합성을 이용하는 것이 좋은데, 이번에는 왜 합성을 사용해야 하는지에 대해
mangkyu.tistory.com
Design-Pattern-In-Swift/contents/3-Design-Pattern-Problem-Intro.md at main · i-colours-u/Design-Pattern-In-Swift
🎃 디자인패턴을 Swift 관점에서 이해해보기 (With GoF의 디자인패턴) 🎃. Contribute to i-colours-u/Design-Pattern-In-Swift development by creating an account on GitHub.
github.com
'🔗 Architecture & Design Pattern' 카테고리의 다른 글
| [🍔 Design Pattern] 햄버거로 배우는 디자인 패턴 (2) Factory Pattern (1) | 2024.09.04 |
|---|---|
| [Design Pattern] Singleton Pattern (1) | 2024.09.03 |