# 디자인 패턴 1조 # 12월 30일 - Factory Method ### ✏️ 정의 - 생성(Creational) 패턴의 하나로, 객체 생성 처리를 서브 클래스로 분리 해 처리하도록 캡슐화하는 패턴 - 즉, 객체의 생성 코드를 별도의 클래스나 메서드로 분리함으로써 객체 생성의 변화에 대비해는 데 유용하다. - 특정 기능 구현은 개별 클래스를 통해 제공되는 것이 바람직한 설계이다. - 상황에 따라 적절한 객체를 생성하는 코드는 자주 중복될 수 있다. - 객체 생성 방식의 변화는 해당되는 모든 코드 부분을 변경해야 하는 문제가 발생한다. ### ✏️ 역할 ![](https://i.imgur.com/q0QlLXQ.png) - Product - 팩토리 메서드로 생성될 객체의 공통 인터페이스 - Creator와 이를 채택한 객체가 생성할 수 있는 모든 객체의 공통 인터페이스를 선언 - ConcreteProduct - 구체적으로 객체가 생성되는 클래스 - Product가 선언한 인터페이스로 만든 실제 객체 - Creator - 팩토리 메서드를 갖는 프로토콜(클래스여도 됨) - 새로운 객체를 반환하는 팩토리 메서드를 선언 - 여기서 반환하는 객체는 Product 인터페이스를 준수하고 있어야 함 - ConcreteCreator - 팩토리 메서드를 구현하는 객체로 ConcreteProduct 객체를 생성 질리 - https://magnetic-rosehip-bac.notion.site/Factory-Method-c0970cb5885149c795a5eb2b2fd70ee8 ## 참고 링크 - Wonbi - [[Design Pattern] 팩토리 메서드 패턴이란](https://gmlwjd9405.github.io/2018/08/07/factory-method-pattern.html) - zhilly - [Factory Method Pattern - Pingu 블로그](https://icksw.tistory.com/237) - [[디자인 패턴] Factory pattern in Swift - 라이언 블로그](https://velog.io/@ryan-son/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-Factory-pattern-in-Swift) - [GitHub - ochococo/Design-Patterns-In-Swift](https://github.com/ochococo/Design-Patterns-In-Swift#-factory-method) - Ayaan - [객체지향 디자인 패턴2](https://youtu.be/q3_WXP9pPUQ?t=368) - [디자인 패턴 - Factory Method](https://refactoring.guru/ko/design-patterns/factory-method) # 1월 6일 - 추상화 팩토리 ## 참고 링크 - Wonbi - [Design-Pattern-In-Swift](https://github.com/i-colours-u/Design-Pattern-In-Swift) - Ayaan - [객체지향 디자인 패턴2](https://www.youtube.com/watch?v=q3_WXP9pPUQ&t=540s) - [디자인 패턴 - Abstract Factory](https://refactoring.guru/ko/design-patterns/abstract-factory) # 1월 13일 - 프로토타입 ## 참고 링크 - zhilly <details> <summary>자세히보기</summary> <div markdown="1"> # 프로토타입 패턴이란? 프로토타입 패턴의 정의는 코드를 클래스에 종속시키지 않고 기존에 존재하던 객체를 복사할 수 있는 디자인 패턴 ## 언제씀? 어떤 객체가 존재하고 해당 객체와 정확하게 똑같은 객체를 만들고 싶을 때 프로토타입패턴을 사용할 수 있음. 이를 해결하는 가장 간단한 방법은 원본 객체의 모든 값을 가지고 직접 새로운 객체를 만드는 방법임. 단, 이렇게 직접 만드는 경우 접근 제한이 private인 프로퍼티에는 접근할 수 없기 때문에 복사를 하지 못할 수도 있음. 또한 복사본을 만들기 위해 원본 객체의 클래스를 알아야하기 때문에 코드가 해당 클래스에 종속되어 의존성이 발생함. 이러한 상황에서 프로토타입 패턴을 사용할 수 있다. 매번 객체를 직접 만들기 보다는 기존 객체의 정보와 동일한 정보를 갖는 새로운 객체를 생성하는 역할을 하는 프로토타입 클래스를 만들어서 간편하게 사용할 수 있음. 또한 프로토타입 인터페이스를 갖는 객체를 허용하여 클래스 의존성도 해결할 수 있다. ## 어떻게? 클래스와 같은 참조타입을 복사하는 방법에는 얕은 복사, 깊은 복사가 있음. 얕은 복사는 그냥 새로운 변수에 기존 객체를 할당하는 방법. 이렇게 생성한 객체는 기존 객체를 계속 가리키고 있기 때문에 새로운 객체를 만든 것이라 할 수 없음. 따라서 해당 객체의 모든 정보를 동일하게 가진 새로운 객체를 만들기 위해서는 깊은 복사를 해줘야함. 프로토타입 패턴은 이러한 작업을 쉽게 할 수 있도록 도와주는 친구. ## 뭐가 있음? - Prototype - 객체를 복제할 방법을 선언함. - Concrete Prototype - 객체를 복제하는 방법을 실제로 구현하는 곳. - Client - 프로토타입 인터페이스를 따르는 모든 객체의 복제본을 생성할 수 있음. [예제 코드](https://github.com/iDevPingu/Swift_Design_Pattern_Study/tree/main/Creational%20Pattern/Prototype%20Pattern/Prototype%20Pattern) ```swift import UIKit public protocol Prototype: class { init(prototype: Self) } extension Prototype { public func clone() -> Self { return type(of: self).init(prototype: self) } } public class Marin: Prototype { private var health: Int private var attack: Int private var defense: Int public init(health: Int, attack: Int, defense: Int) { self.health = health self.attack = attack self.defense = defense } // 보조 이니셜라이저 public required convenience init(prototype: Marin) { self.init(health: prototype.health, attack: prototype.attack, defense: prototype.defense) } func printStatus() { print("Marin Health: \(health) Attack: \(attack) Defense: \(defense)") } func add(health: Int) { self.health += health } } public class Medic: Prototype { private var health: Int private var mana: Int private var defense: Int public init(health: Int, mana: Int, defense: Int) { self.health = health self.mana = mana self.defense = defense } public required convenience init(prototype: Medic) { self.init(health: prototype.health, mana: prototype.mana, defense: prototype.defense) } func printStatus() { print("Medic Health: \(health) Mana: \(mana) Defense: \(defense)\n") } } var marin = Marin(health: 40, attack: 5, defense: 1) var shallowCopyMarin = marin var deepCopyMarin = marin.clone() shallowCopyMarin.add(health: 7) //deepCopyMarin.defense += 5 marin.printStatus() deepCopyMarin.printStatus() var marinAddress: UnsafeMutablePointer<Marin> = .init(&marin) var shallowCopyMarinAddress: UnsafeMutablePointer<Marin> = .init(&shallowCopyMarin) var deepCopyMarinAddress: UnsafeMutablePointer<Marin> = .init(&deepCopyMarin) print("원본 마린 주소 : \(marinAddress)") print("얕은 복사 마린 주소 : \(shallowCopyMarinAddress)") print("깊은 복사 마린 주소 : \(deepCopyMarinAddress)") ``` </div> </details>