SlideShare a Scribd company logo
1 of 30
Download to read offline
객체지향 in Swift
2019.12.21 SAT

DDD iOS 최혜선, 조준영
객체지향 패러다임
객체

object
2
객체지향 패러다임
우리가 알고 있던 객체지향

"현실 세계에서 식별 가능한 개체 또는 사물은 모두 '상태'와 '행동'을
가진 객체로 볼 수 있고, 이를 소프트웨어 세계에 모방해놓은 것이 객
체지향이다."
객체지향은 현실 세계를 모방했다?
3
객체지향 패러다임
☕
양을 늘리자!
온도를 높이자!
현실세계

수동적
객체지향 세계

자율적
객체지향의 목적은 새로운 세계를 창조하는 것
4
자율적인 객체
상태(state)와 행동(behavior)을 가지고 스스로 판단하는 자율적인 존재

특징

캡슐화

- 객체 내부의 세부 사항을 감추는 것

- 행동을 외부에 공개하여 메시지를 통해 상호작용

응집도가 높은 객체

- 스스로 자신의 데이터를 처리하는 자율적인 존재

- 밀접하게 연관된 작업만을 수행하고 연관성이 없는 작업은 다른 객체에게 위임
메세지를 통해서만 협력하는 자율적인 객체들의 공동체 만들기
5
자율적인 객체
캡슐화 응집도가 높은 객체

각 항목은 연관있는 것들끼리 모여있음
6
자판기 속 객체지향
자판기는 아래와 같은 과정을 가집니다
캡슐화
1. 소비자가 돈을 넣는다
2. 넣은 돈으로 구매할 수 있는 메뉴에 LED가 켜진다
3. 소비자가 메뉴를 선택한다
4. 자판기 내부에서 종이컵을 외부로 내보낸다
5. 뜨거운 물을 적정량 붓는다
6. 원료를 종이컵에 투입한다
7. 컵을 회전시켜 내용물을 섞는다
8. 소비자는 컵을 가져간다
7
자판기 속 객체지향
👤
소비자 객체
자판기 객체
☕ 🍵
아메리카노 객체
라떼 객체
소비자는 자판기의 

메뉴를 선택할 수 있다
소비자는 자판기에

돈을 넣는다
음료를 제조한다
MENU

JDF!아메리카노!
IPU!아메리카노!
JDF!라떼!
IPU!라떼
메뉴판 객체
메뉴 항목

객체들
자율적인 객체들이 모여 협력을 이루는 모습
8
역할, 책임, 협력
역할

- 어떤 협력에 참여하는 특정한 사람이 협력 안에서 차지하는 책임이
나 의무를 의미

- 소비자라는 역할을 맡은 사람은 음료를 구매해야 함

- 자판기는 주문된 음료를 제조하거나 재고에서 가져와 배출하는 책
임이 있음
9
역할, 책임, 협력
책임

- 어떤 객체가 요청에 대해 대답해줄 수 있거나, 적절한 행동을 할 의
무가 있는 경우 해당 객체가 책임을 가진다고 한다

- 객체에 의해 정의되는 응집도 있는 행위의 집합
10
역할, 책임, 협력
크레이그 라만 (Craig Larman)

"객체지향 개발에서 가장 중요한 능력은 책임을
능숙하게 소프트웨어 객체에 할당하는 것"
11
역할, 책임, 협력
🙋
하는 것(doing)
🧑🎓
아는 것(knowing)
•객체를 생성하거나 계산을 하는 등의
스스로 하는 것

•다른 객체의 행동을 시작시키는 것

•다른 객체의 활동을 제어하고 조절하
는 것
•개인적인 정보에 관해 아는 것

•관련된 객체에 관해 아는 것

•자신이 유도하거나 계산할 수 있는 것
에 관해 아는 것
객체의 책임은 두 가지로 구성된다!
12
역할, 책임, 협력
협력

- 다수의 요청과 응답으로 구성되며 전체적으로 협력은 다수의 연쇄
적인 요청과 응답의 흐름으로 구성

- 요청과 응답은 협력에 참여하는 객체가 수행할 책임을 정의
소비자 자판기
음료를 선택한다
음료를 제조한다
요청
응답13
역할, 책임, 협력
👤
소비자 객체 자판기 객체
☕🧃
음료 객체
MENU
메뉴판 객체
객체
역할 소비자는 음료를 구매한다 음료 주문을 받는다
소비자에게 

메뉴를 전달한다

(자판기의 LED)
책임
소비자는 자판기에 

돈을 넣는다

소비자는 자판기의 

메뉴를 선택한다
음료를 제조한다

음료를 배출한다
소비자의 선택을 받는다
협력의 결과
자율적인 객체들이 모여 협력을 이루는 모습
14
15
객체지향 설계 SOLID 원칙
“유지 보수와 확장이 쉬운 소프트웨어를 만들기 위한 객체 지향 설계 원칙”
- Single Responsibility Principle

- Open Closed Principle

- Liskov Substitution Principle

- Interface Segregation Principle

- Dependency Inversion Principle
Single Responsibility Principle
로버트 마틴은 모듈의 응집도가 변경과 연관이 있다는 것을 강조하기 위해 SRP 제시
“클래스는 단 한가지의 변경 이유만 가져야 한다.”
16
코드의 가독성 향상
유지보수 용이
책임을 적절히 분배함으로써 ✅
✅
단일 책임 원칙
class InstagramManager {
fileprivate func request() -> Data {
// Instagram API에 대한 요청
return Data()
}
fileprivate func convertJsonToModel(with data: Data) -> [AnyObject] {
// JSON을 모델로 변환한다.
return [AnyObject]()
}
fileprivate func saveInCoreData(with models: [AnyObject]) {
// 코어 데이터에 저장한다.
}
public func create() {
let data = request()
let model = convertJsonToModel(with: data)
saveInCoreData(with: model)
}
}
변경 전
17
class RequestManager {
func request() -> Data{
// Instagram API에 대한 요청
return Data()
}
}
class ParseManager {
func convertJsonToModel(with data: Data) -> [AnyObject] {
// JSON을 모델로 변환한다.
return [AnyObject]()
}
}
class CoreDataManager {
fileprivate func saveInCoreData(with models: [AnyObject]) {
// 코어 데이터에 저장한다.
}
}
class InstagramManager {
fileprivate let requestManager: RequestManager
fileprivate let parse: ParseManager
fileprivate let coreManager: CoreDataManager
init(requestManager: RequestManager, parseManager: ParseManager, coreManager: CoreDataManager) {
self.requestManager = requestManager
self.parse = parseManager
self.coreManager = coreManager
}
func create() {
let data = self.requestManager.request()
let objects = self.parse.convertJsonToModel(with: data)
coreManager.saveInCoreData(with: objects)
}
}
변경 후
18
변경의 이유를 파악하는 2가지
응집도가 높은 클래스는 인스턴스를 생성할 때 모든 속성을 생성자를 통해 초기화한다.
부분적으로 초기화되지 않는 속성이 있다면 초기화되는 속성을 기준으로 코드를 분리해야 한다.
1. 인스턴스 변수의 초기화 시점
모든 메서드가 모든 속성을 사용한다면 응집도가 높다고 할 수 있다.
하지만 메서드들이 사용하는 속성에 따라 그룹이 나뉜다면 응집도가 낮다고 볼 수 있으며

메서드가 사용하는 속성 그룹을 기준으로 코드를 분리해야 한다.
2. 메서드들이 인스턴스 변수를 사용하는 방식
19
SRP 위반의 악취
- 여러 원인에 의한 변경 (Divergent change)
- 산탄총 수술 (Shotgun surgery)
응집성을 높이는 작업으로 산발적으로 여러 곳에 분포된 책임들을 한 곳에 모
으면서 설계를 깨끗하게 하는 것
하나의 클래스에 여러 책임이 혼재되어 있어 각각의 개별 클래스로 분할하는 것
분리된 클래스간의 관계에 복잡도를 줄이도록 설계한다. 만약 분리된 클래스
가 유사하고 비슷한 책임을 중복해서 갖고 있다면 슈퍼클래스를 사용할 수 있
다.
이럴만한 클래스가 없다면 새로운 클래스를 만들어 해결
Open Close Principle
21
“클래스는 확장에 열려있어야 하고, 수정에 대해서는 닫혀있어야 한다.”
요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야 하
며, 기존 구성요소를 쉽게 확장해 재사용할 수 있어야 한다.
OCP 중요 메커니즘 추상화
다형성
개방 폐쇄 원칙
✅
✅
22
변경 전
class Dog {
func cryingSound() -> String {
return "멍멍"
}
}
class Cat {
func cryingSound() -> String {
return "야옹"
}
}
func printCryingSound(of animal: Any) {
if let dog = animal as? Dog {
print(dog.cryingSound())
} else if let cat = animal as? Cat {
print(cat.cryingSound())
}
}
변경 후
protocol Cryable {
func cryingSound() -> String
}
class Dog: Cryable {
func cryingSound() -> String {
return "멍멍"
}
}
class Cat: Cryable {
func cryingSound() -> String {
return "야옹"
}
}
func printCryingSound(of animal: Cryable) {
print(animal.cryingSound())
}
23
Liskov Substitution Principle
“서브 타입은 언제나 기반 타입으로 교체할 수 있어야 한다.”
특징
자식 클래스는 부모 클래스에서 가능한 행위를 수행할 수 있어야 한다.✅
부모 클래스의 책임을 재정의하고 확장을 수행해야 한다.✅
리스코프 치환 원칙
24
class Rectangle {
var width: Float = 0
var length: Float = 0
var area: Float {
return width * length
}
}
class Square: Rectangle {
override var width: Float {
didSet {
length = width
}
}
}
func printArea(of rectangle: Rectangle) {
rectangle.width = 2
rectangle.length = 5
print(rectangle.area)
}
let rectangle = Rectangle()
printArea(of: rectangle)
let square = Square()
printArea(of: square)
변경 전 변경 후
protocol Polygon {
var area: Float { get }
}
class Rectangle: Polygon {
var width: Float
var length: Float
var area: Float {
return width * length
}
init(width: Float, length: Float) {
self.width = width
self.length = length
}
}
class Square: Polygon {
var sideLength: Float
var area: Float {
return sideLength * sideLength
}
init(sideLength: Float) {
self.sideLength = sideLength
}
}
25
Interface Segregation Principle
“한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다.”
특징
어떤 클래스의 특정 부분집합만을 이용한다면, 이들을 따로 인터페이스로 분리한다.✅
하나의 일반적인 인터페이스 보다는 여러 개의 구체적인 인터페이스가 낫다.✅
SRP가 클래스의 단일책임을 강조한다면 ISP는 인터페이스의 단일책임을 강조한다.✅
인터페이스 분리 법칙
26
변경 전 변경 후
protocol GestureProtocol {
func didTap()
func didDoubleTap()
func didLongPress()
}
class MyButton: GestureProtocol {
func didTap() {
// 탭 액션
}
func didDoubleTap() {
// 더블 탭 액션
}
func didLongPress() {
// 롱 프레스 액션
}
}
protocol TapProtocol {
func didTap()
}
protocol DoubleTapProtocol {
func didDoubleTap()
}
protocol LongPressProtocol {
func didLongPress()
}
class MyButton: TapProtocol, DoubleTapProtocol,
LongPressProtocol {
func didTap() {
// 탭 액션
}
func didDoubleTap() {
// 더블 탭 액션
}
func didLongPress() {
// 롱 프레스 액션
}
}
27
Dependency Inversion Principle
의존관계 역전 원칙
특징
변화하기 쉬운 구체적인 클래스 보다 변화하기 어려운 추상 클래스 혹은 인터페이스에 의존한다.✅
“상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.”
DIP를 만족하면 ‘의존성 주입’ 이라는 기술로 변화에 유연한 설계를 할 수 있다.✅
28
Dependency Injection
의존성 주입
- 의존성
- 주입
의존 관계를 가지고 있다. 예시) A 클래스 내부 변수로 B 클래스를 가지고 있다.
내부가 아니라 외부에서 객체를 생성해서 넣어 준다.
+ 의존성 분리
의존관계 역전 원칙을 통해 의존관계 분리
상위 계층이 하위 계층에 의존하고 있는 것을 반전시켜 하위 계층의 구현으로 부터 독립시킨
다.
의존성을 주입할 때 구체 클래스가 아닌 프로토콜을 사용해 의존관계를 독립시킨다.
29
변경 전
class Handler {
let fm = FilesystemManager()
func handle(string: String) {
fm.save(string: string)
}
}
class FilesystemManager {
func save(string: String) {
// 파일을 연다.
// 파일에 문자열을 저장한다.
// 파일을 닫는다.
}
}
변경 후
protocol Storage {
func save(string: String)
}
class Handler {
let storage: Storage
init(storage: Storage) {
self.storage = storage
}
func handle(string: String) {
storage.save(string: string)
}
}
class FilesystemManager: Storage {
func save(string: String) {
// 파일을 연다.
// 파일에 문자열을 저장한다.
// 파일을 닫는다.
}
}
참고자료
•도서 : 객체지향의 사실과 오해

•도서 : 오브젝트 (코드로 이해하는 객체지향 설계)

•https://velog.io/@wltn3231/객체지향-개발-원칙-SOLID

•https://medium.com/@jgj455/오늘의-swift-상식-객체와-solid-원
칙-270415c64b64

•https://medium.com/@jang.wangsu/di-dependency-injection-이
란-1b12fdefec4f

•https://soojin.ro/blog/solid-principles-in-swift

•https://jupiny.com/2019/01/12/object-orientation-fact-and-
misunderstanding/
30

More Related Content

What's hot

Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2José Paumard
 
Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...
Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...
Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...Ripple Labs
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Expressjguerrero999
 
Testing with JUnit 5 and Spring
Testing with JUnit 5 and SpringTesting with JUnit 5 and Spring
Testing with JUnit 5 and SpringVMware Tanzu
 
Cross-domain requests with CORS
Cross-domain requests with CORSCross-domain requests with CORS
Cross-domain requests with CORSVladimir Dzhuvinov
 
Type script - advanced usage and practices
Type script  - advanced usage and practicesType script  - advanced usage and practices
Type script - advanced usage and practicesIwan van der Kleijn
 
Indexing with MongoDB
Indexing with MongoDBIndexing with MongoDB
Indexing with MongoDBMongoDB
 
Apache Jackrabbit Oak on MongoDB
Apache Jackrabbit Oak on MongoDBApache Jackrabbit Oak on MongoDB
Apache Jackrabbit Oak on MongoDBMongoDB
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)Scott Wlaschin
 
Fast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaCharles Nutter
 
Let's read code: the python-requests library
Let's read code: the python-requests libraryLet's read code: the python-requests library
Let's read code: the python-requests librarySusan Tan
 
Introduction to .NET Core
Introduction to .NET CoreIntroduction to .NET Core
Introduction to .NET CoreMarco Parenzan
 
SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)Bernardo Damele A. G.
 
Client-side JavaScript
Client-side JavaScriptClient-side JavaScript
Client-side JavaScriptLilia Sfaxi
 
体系的に学ばないXSSの話
体系的に学ばないXSSの話体系的に学ばないXSSの話
体系的に学ばないXSSの話Yutaka Maehira
 

What's hot (20)

Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...
Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...
Everything You Ever Wanted to Know About Move Semantics, Howard Hinnant, Accu...
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
Testing with JUnit 5 and Spring
Testing with JUnit 5 and SpringTesting with JUnit 5 and Spring
Testing with JUnit 5 and Spring
 
Rust
RustRust
Rust
 
Cross-domain requests with CORS
Cross-domain requests with CORSCross-domain requests with CORS
Cross-domain requests with CORS
 
Node js for beginners
Node js for beginnersNode js for beginners
Node js for beginners
 
Type script - advanced usage and practices
Type script  - advanced usage and practicesType script  - advanced usage and practices
Type script - advanced usage and practices
 
Indexing with MongoDB
Indexing with MongoDBIndexing with MongoDB
Indexing with MongoDB
 
Sql Injection Myths and Fallacies
Sql Injection Myths and FallaciesSql Injection Myths and Fallacies
Sql Injection Myths and Fallacies
 
Apache Jackrabbit Oak on MongoDB
Apache Jackrabbit Oak on MongoDBApache Jackrabbit Oak on MongoDB
Apache Jackrabbit Oak on MongoDB
 
The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)The Functional Programmer's Toolkit (NDC London 2019)
The Functional Programmer's Toolkit (NDC London 2019)
 
JavaScript: Events Handling
JavaScript: Events HandlingJavaScript: Events Handling
JavaScript: Events Handling
 
Fast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible Java
 
Let's read code: the python-requests library
Let's read code: the python-requests libraryLet's read code: the python-requests library
Let's read code: the python-requests library
 
Introduction to .NET Core
Introduction to .NET CoreIntroduction to .NET Core
Introduction to .NET Core
 
BDD: Cucumber + Selenium + Java
BDD: Cucumber + Selenium + JavaBDD: Cucumber + Selenium + Java
BDD: Cucumber + Selenium + Java
 
SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)
 
Client-side JavaScript
Client-side JavaScriptClient-side JavaScript
Client-side JavaScript
 
体系的に学ばないXSSの話
体系的に学ばないXSSの話体系的に学ばないXSSの話
体系的に学ばないXSSの話
 

Similar to 객체지향 설계

ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는Taegon Kim
 
5-3. html5 device access
5-3. html5 device access5-3. html5 device access
5-3. html5 device accessJinKyoungHeo
 
Flipper 불완전 정복
Flipper 불완전 정복Flipper 불완전 정복
Flipper 불완전 정복Sewon Ann
 
안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트병한 유
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8Sangmin Lee
 
DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)beom kyun choi
 
04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조Wanbok Choi
 
Jlook open api platform-appdevguide
Jlook open api platform-appdevguideJlook open api platform-appdevguide
Jlook open api platform-appdevguideHongSeong Jeon
 
Design patterns
Design patternsDesign patterns
Design patternsdf
 
MyBatis에서 JPA로
MyBatis에서 JPA로MyBatis에서 JPA로
MyBatis에서 JPA로Dongmin Shin
 
Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조Sangon Lee
 
[2018] MyBatis에서 JPA로
[2018] MyBatis에서 JPA로[2018] MyBatis에서 JPA로
[2018] MyBatis에서 JPA로NHN FORWARD
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Ryan Park
 
막하는 스터디 네 번째 만남 AngularJs (20151108)
막하는 스터디 네 번째 만남 AngularJs (20151108)막하는 스터디 네 번째 만남 AngularJs (20151108)
막하는 스터디 네 번째 만남 AngularJs (20151108)연웅 조
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It종빈 오
 

Similar to 객체지향 설계 (20)

ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는
 
5-3. html5 device access
5-3. html5 device access5-3. html5 device access
5-3. html5 device access
 
[Codelab 2017] ReactJS 기초
[Codelab 2017] ReactJS 기초[Codelab 2017] ReactJS 기초
[Codelab 2017] ReactJS 기초
 
Flipper 불완전 정복
Flipper 불완전 정복Flipper 불완전 정복
Flipper 불완전 정복
 
javascript03
javascript03javascript03
javascript03
 
안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트안드로이드 개발자를 위한 스위프트
안드로이드 개발자를 위한 스위프트
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)DDD 구현기초 (거의 Final 버전)
DDD 구현기초 (거의 Final 버전)
 
04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조04 안드로이드 응용프로그램의 구조
04 안드로이드 응용프로그램의 구조
 
Jlook open api platform-appdevguide
Jlook open api platform-appdevguideJlook open api platform-appdevguide
Jlook open api platform-appdevguide
 
Design patterns
Design patternsDesign patterns
Design patterns
 
MyBatis에서 JPA로
MyBatis에서 JPA로MyBatis에서 JPA로
MyBatis에서 JPA로
 
Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조
 
react-ko.pdf
react-ko.pdfreact-ko.pdf
react-ko.pdf
 
[2018] MyBatis에서 JPA로
[2018] MyBatis에서 JPA로[2018] MyBatis에서 JPA로
[2018] MyBatis에서 JPA로
 
Eclipse RCP 1/2
Eclipse RCP 1/2Eclipse RCP 1/2
Eclipse RCP 1/2
 
Hacosa j query 8th
Hacosa j query 8thHacosa j query 8th
Hacosa j query 8th
 
Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005Working Effectively With Legacy Code - xp2005
Working Effectively With Legacy Code - xp2005
 
막하는 스터디 네 번째 만남 AngularJs (20151108)
막하는 스터디 네 번째 만남 AngularJs (20151108)막하는 스터디 네 번째 만남 AngularJs (20151108)
막하는 스터디 네 번째 만남 AngularJs (20151108)
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
 

객체지향 설계

  • 1. 객체지향 in Swift 2019.12.21 SAT DDD iOS 최혜선, 조준영
  • 3. 객체지향 패러다임 우리가 알고 있던 객체지향 "현실 세계에서 식별 가능한 개체 또는 사물은 모두 '상태'와 '행동'을 가진 객체로 볼 수 있고, 이를 소프트웨어 세계에 모방해놓은 것이 객 체지향이다." 객체지향은 현실 세계를 모방했다? 3
  • 4. 객체지향 패러다임 ☕ 양을 늘리자! 온도를 높이자! 현실세계 수동적 객체지향 세계 자율적 객체지향의 목적은 새로운 세계를 창조하는 것 4
  • 5. 자율적인 객체 상태(state)와 행동(behavior)을 가지고 스스로 판단하는 자율적인 존재 특징 캡슐화 - 객체 내부의 세부 사항을 감추는 것 - 행동을 외부에 공개하여 메시지를 통해 상호작용 응집도가 높은 객체 - 스스로 자신의 데이터를 처리하는 자율적인 존재 - 밀접하게 연관된 작업만을 수행하고 연관성이 없는 작업은 다른 객체에게 위임 메세지를 통해서만 협력하는 자율적인 객체들의 공동체 만들기 5
  • 6. 자율적인 객체 캡슐화 응집도가 높은 객체 각 항목은 연관있는 것들끼리 모여있음 6
  • 7. 자판기 속 객체지향 자판기는 아래와 같은 과정을 가집니다 캡슐화 1. 소비자가 돈을 넣는다 2. 넣은 돈으로 구매할 수 있는 메뉴에 LED가 켜진다 3. 소비자가 메뉴를 선택한다 4. 자판기 내부에서 종이컵을 외부로 내보낸다 5. 뜨거운 물을 적정량 붓는다 6. 원료를 종이컵에 투입한다 7. 컵을 회전시켜 내용물을 섞는다 8. 소비자는 컵을 가져간다 7
  • 8. 자판기 속 객체지향 👤 소비자 객체 자판기 객체 ☕ 🍵 아메리카노 객체 라떼 객체 소비자는 자판기의 메뉴를 선택할 수 있다 소비자는 자판기에 돈을 넣는다 음료를 제조한다 MENU JDF!아메리카노! IPU!아메리카노! JDF!라떼! IPU!라떼 메뉴판 객체 메뉴 항목 객체들 자율적인 객체들이 모여 협력을 이루는 모습 8
  • 9. 역할, 책임, 협력 역할 - 어떤 협력에 참여하는 특정한 사람이 협력 안에서 차지하는 책임이 나 의무를 의미 - 소비자라는 역할을 맡은 사람은 음료를 구매해야 함 - 자판기는 주문된 음료를 제조하거나 재고에서 가져와 배출하는 책 임이 있음 9
  • 10. 역할, 책임, 협력 책임 - 어떤 객체가 요청에 대해 대답해줄 수 있거나, 적절한 행동을 할 의 무가 있는 경우 해당 객체가 책임을 가진다고 한다 - 객체에 의해 정의되는 응집도 있는 행위의 집합 10
  • 11. 역할, 책임, 협력 크레이그 라만 (Craig Larman) "객체지향 개발에서 가장 중요한 능력은 책임을 능숙하게 소프트웨어 객체에 할당하는 것" 11
  • 12. 역할, 책임, 협력 🙋 하는 것(doing) 🧑🎓 아는 것(knowing) •객체를 생성하거나 계산을 하는 등의 스스로 하는 것 •다른 객체의 행동을 시작시키는 것 •다른 객체의 활동을 제어하고 조절하 는 것 •개인적인 정보에 관해 아는 것 •관련된 객체에 관해 아는 것 •자신이 유도하거나 계산할 수 있는 것 에 관해 아는 것 객체의 책임은 두 가지로 구성된다! 12
  • 13. 역할, 책임, 협력 협력 - 다수의 요청과 응답으로 구성되며 전체적으로 협력은 다수의 연쇄 적인 요청과 응답의 흐름으로 구성 - 요청과 응답은 협력에 참여하는 객체가 수행할 책임을 정의 소비자 자판기 음료를 선택한다 음료를 제조한다 요청 응답13
  • 14. 역할, 책임, 협력 👤 소비자 객체 자판기 객체 ☕🧃 음료 객체 MENU 메뉴판 객체 객체 역할 소비자는 음료를 구매한다 음료 주문을 받는다 소비자에게 메뉴를 전달한다 (자판기의 LED) 책임 소비자는 자판기에 돈을 넣는다 소비자는 자판기의 메뉴를 선택한다 음료를 제조한다 음료를 배출한다 소비자의 선택을 받는다 협력의 결과 자율적인 객체들이 모여 협력을 이루는 모습 14
  • 15. 15 객체지향 설계 SOLID 원칙 “유지 보수와 확장이 쉬운 소프트웨어를 만들기 위한 객체 지향 설계 원칙” - Single Responsibility Principle - Open Closed Principle - Liskov Substitution Principle - Interface Segregation Principle - Dependency Inversion Principle
  • 16. Single Responsibility Principle 로버트 마틴은 모듈의 응집도가 변경과 연관이 있다는 것을 강조하기 위해 SRP 제시 “클래스는 단 한가지의 변경 이유만 가져야 한다.” 16 코드의 가독성 향상 유지보수 용이 책임을 적절히 분배함으로써 ✅ ✅ 단일 책임 원칙
  • 17. class InstagramManager { fileprivate func request() -> Data { // Instagram API에 대한 요청 return Data() } fileprivate func convertJsonToModel(with data: Data) -> [AnyObject] { // JSON을 모델로 변환한다. return [AnyObject]() } fileprivate func saveInCoreData(with models: [AnyObject]) { // 코어 데이터에 저장한다. } public func create() { let data = request() let model = convertJsonToModel(with: data) saveInCoreData(with: model) } } 변경 전 17
  • 18. class RequestManager { func request() -> Data{ // Instagram API에 대한 요청 return Data() } } class ParseManager { func convertJsonToModel(with data: Data) -> [AnyObject] { // JSON을 모델로 변환한다. return [AnyObject]() } } class CoreDataManager { fileprivate func saveInCoreData(with models: [AnyObject]) { // 코어 데이터에 저장한다. } } class InstagramManager { fileprivate let requestManager: RequestManager fileprivate let parse: ParseManager fileprivate let coreManager: CoreDataManager init(requestManager: RequestManager, parseManager: ParseManager, coreManager: CoreDataManager) { self.requestManager = requestManager self.parse = parseManager self.coreManager = coreManager } func create() { let data = self.requestManager.request() let objects = self.parse.convertJsonToModel(with: data) coreManager.saveInCoreData(with: objects) } } 변경 후 18
  • 19. 변경의 이유를 파악하는 2가지 응집도가 높은 클래스는 인스턴스를 생성할 때 모든 속성을 생성자를 통해 초기화한다. 부분적으로 초기화되지 않는 속성이 있다면 초기화되는 속성을 기준으로 코드를 분리해야 한다. 1. 인스턴스 변수의 초기화 시점 모든 메서드가 모든 속성을 사용한다면 응집도가 높다고 할 수 있다. 하지만 메서드들이 사용하는 속성에 따라 그룹이 나뉜다면 응집도가 낮다고 볼 수 있으며 메서드가 사용하는 속성 그룹을 기준으로 코드를 분리해야 한다. 2. 메서드들이 인스턴스 변수를 사용하는 방식 19
  • 20. SRP 위반의 악취 - 여러 원인에 의한 변경 (Divergent change) - 산탄총 수술 (Shotgun surgery) 응집성을 높이는 작업으로 산발적으로 여러 곳에 분포된 책임들을 한 곳에 모 으면서 설계를 깨끗하게 하는 것 하나의 클래스에 여러 책임이 혼재되어 있어 각각의 개별 클래스로 분할하는 것 분리된 클래스간의 관계에 복잡도를 줄이도록 설계한다. 만약 분리된 클래스 가 유사하고 비슷한 책임을 중복해서 갖고 있다면 슈퍼클래스를 사용할 수 있 다. 이럴만한 클래스가 없다면 새로운 클래스를 만들어 해결
  • 21. Open Close Principle 21 “클래스는 확장에 열려있어야 하고, 수정에 대해서는 닫혀있어야 한다.” 요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야 하 며, 기존 구성요소를 쉽게 확장해 재사용할 수 있어야 한다. OCP 중요 메커니즘 추상화 다형성 개방 폐쇄 원칙 ✅ ✅
  • 22. 22 변경 전 class Dog { func cryingSound() -> String { return "멍멍" } } class Cat { func cryingSound() -> String { return "야옹" } } func printCryingSound(of animal: Any) { if let dog = animal as? Dog { print(dog.cryingSound()) } else if let cat = animal as? Cat { print(cat.cryingSound()) } } 변경 후 protocol Cryable { func cryingSound() -> String } class Dog: Cryable { func cryingSound() -> String { return "멍멍" } } class Cat: Cryable { func cryingSound() -> String { return "야옹" } } func printCryingSound(of animal: Cryable) { print(animal.cryingSound()) }
  • 23. 23 Liskov Substitution Principle “서브 타입은 언제나 기반 타입으로 교체할 수 있어야 한다.” 특징 자식 클래스는 부모 클래스에서 가능한 행위를 수행할 수 있어야 한다.✅ 부모 클래스의 책임을 재정의하고 확장을 수행해야 한다.✅ 리스코프 치환 원칙
  • 24. 24 class Rectangle { var width: Float = 0 var length: Float = 0 var area: Float { return width * length } } class Square: Rectangle { override var width: Float { didSet { length = width } } } func printArea(of rectangle: Rectangle) { rectangle.width = 2 rectangle.length = 5 print(rectangle.area) } let rectangle = Rectangle() printArea(of: rectangle) let square = Square() printArea(of: square) 변경 전 변경 후 protocol Polygon { var area: Float { get } } class Rectangle: Polygon { var width: Float var length: Float var area: Float { return width * length } init(width: Float, length: Float) { self.width = width self.length = length } } class Square: Polygon { var sideLength: Float var area: Float { return sideLength * sideLength } init(sideLength: Float) { self.sideLength = sideLength } }
  • 25. 25 Interface Segregation Principle “한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다.” 특징 어떤 클래스의 특정 부분집합만을 이용한다면, 이들을 따로 인터페이스로 분리한다.✅ 하나의 일반적인 인터페이스 보다는 여러 개의 구체적인 인터페이스가 낫다.✅ SRP가 클래스의 단일책임을 강조한다면 ISP는 인터페이스의 단일책임을 강조한다.✅ 인터페이스 분리 법칙
  • 26. 26 변경 전 변경 후 protocol GestureProtocol { func didTap() func didDoubleTap() func didLongPress() } class MyButton: GestureProtocol { func didTap() { // 탭 액션 } func didDoubleTap() { // 더블 탭 액션 } func didLongPress() { // 롱 프레스 액션 } } protocol TapProtocol { func didTap() } protocol DoubleTapProtocol { func didDoubleTap() } protocol LongPressProtocol { func didLongPress() } class MyButton: TapProtocol, DoubleTapProtocol, LongPressProtocol { func didTap() { // 탭 액션 } func didDoubleTap() { // 더블 탭 액션 } func didLongPress() { // 롱 프레스 액션 } }
  • 27. 27 Dependency Inversion Principle 의존관계 역전 원칙 특징 변화하기 쉬운 구체적인 클래스 보다 변화하기 어려운 추상 클래스 혹은 인터페이스에 의존한다.✅ “상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.” DIP를 만족하면 ‘의존성 주입’ 이라는 기술로 변화에 유연한 설계를 할 수 있다.✅
  • 28. 28 Dependency Injection 의존성 주입 - 의존성 - 주입 의존 관계를 가지고 있다. 예시) A 클래스 내부 변수로 B 클래스를 가지고 있다. 내부가 아니라 외부에서 객체를 생성해서 넣어 준다. + 의존성 분리 의존관계 역전 원칙을 통해 의존관계 분리 상위 계층이 하위 계층에 의존하고 있는 것을 반전시켜 하위 계층의 구현으로 부터 독립시킨 다. 의존성을 주입할 때 구체 클래스가 아닌 프로토콜을 사용해 의존관계를 독립시킨다.
  • 29. 29 변경 전 class Handler { let fm = FilesystemManager() func handle(string: String) { fm.save(string: string) } } class FilesystemManager { func save(string: String) { // 파일을 연다. // 파일에 문자열을 저장한다. // 파일을 닫는다. } } 변경 후 protocol Storage { func save(string: String) } class Handler { let storage: Storage init(storage: Storage) { self.storage = storage } func handle(string: String) { storage.save(string: string) } } class FilesystemManager: Storage { func save(string: String) { // 파일을 연다. // 파일에 문자열을 저장한다. // 파일을 닫는다. } }
  • 30. 참고자료 •도서 : 객체지향의 사실과 오해 •도서 : 오브젝트 (코드로 이해하는 객체지향 설계) •https://velog.io/@wltn3231/객체지향-개발-원칙-SOLID •https://medium.com/@jgj455/오늘의-swift-상식-객체와-solid-원 칙-270415c64b64 •https://medium.com/@jang.wangsu/di-dependency-injection-이 란-1b12fdefec4f •https://soojin.ro/blog/solid-principles-in-swift •https://jupiny.com/2019/01/12/object-orientation-fact-and- misunderstanding/ 30