Main 분리
추상 팩토리
추상 팩토리 패턴은 다음과 같이 5가지 종류로 분류된다.
여러 객체를 특정 클래스에 의존하지 않고 만들 수 있게 해주기 위해 사용된다.
// AbstractFactory는 'SnackFactory'이다.
// 추상화 공장으로 **이 공장은 추상화 제품을 찍어내는 역할**을 한다.
protocol SnackFactory {
func createSnack() -> Snack
}
// AbstractProduct는 'Snack'이다.
// 추상화 제품으로, 어떤 제품이든 이름을 붙여 생산할 수 있다.
protocol Snack {
var name: String { get }
}
// ConcreteFactory는 'ChocolateFactory'와 'CandyFactory'이다.
// 추상화 공장을 초콜릿 공장과 사탕 공장으로 구체화시켰다.
// 구체적 공장은 구체적 제품을 생산하는 역할을 한다.
class ChocolateFactory: SnackFactory {
func createSnack() -> Snack {
return Chocolate()
}
}
class CandyFactory: SnackFactory {
func createSnack() -> Snack {
return Candy()
}
}
// ConcreteProduct는 'Chocolate'와 'Candy'이다.
// 추상화 제품을 초콜릿과 사탕으로 구체화시켰다.
class Chocolate: Snack {
var name: String {
return "초콜릿"
}
}
class Candy: Snack {
var name: String {
return "사탕"
}
}
// Client는 실제로 이 팩토리를 사용하는 코드 부분입니다.
let chocolateFactory = ChocolateFactory()
let chocolate = chocolateFactory.createSnack()
print(chocolate.name) // 출력: 초콜릿
let candyFactory = CandyFactory()
let candy = candyFactory.createSnack()
print(candy.name) // 출력: 사탕
class A부품 {
var name: String = "A 부품"
}
// C완성품 A부품에게 의존하는 상태이다.
// 왜냐하면 A부품의 저장 속성이 변경되면 (name에서 nameString으로 변경되면)
// C완성품의 메소드 내에 있는 저장속성도 변경해주어야 하기 때문이다.
// C완성품이 A부품에게 의존하고 있기 때문에 이런 현상이 발생하는 것이다.
class C완성품 {
var a: A부품 = A부품()
private func printName() {
print(a.name)
}
}
C완성품 => 의존 => A부품 ⭐️⭐️
================================================================================
protocol 모듈화된부품 {
var name: String { get set }
}
class A부품: 모듈화된부품 {
var name: String = "A 부품"
}
class B부품: 모듈화된부품 {
var name: String = "B 부품"
}
class C완성품 {
var moduled: 모듈화된부품
init(moduled: 모듈화된부품) {
self.moduled = moduled
}
private func printName() {
print(moduled.name)
}
}
let moduledA = A부품()
let moduledB = B부품()
let cmoduledA = C완성품(moduled: moduledA)
let cmoduledB = C완성품(moduled: moduledB)
cmoduledA.printName() // "A 부품"
cmoduledB.printName() // "B 부품"
A부품
C완성품 - 모듈화된부품 <= 의존 <= 의존관계의 역전이 일어남 ⭐️⭐️
B부품
// 관심사가 분리되지 않은 코드
// 한 클래스가 사용자의 이름을 "입력하는 역할"과 "출력하는 역할"을 동시에 하고 있다.
class NameSettingController {
func enterName(_ name: String) {
// 사용자 이름 입력
let userName = name
// 사용자 이름 출력
print("Hello, \(userName)!")
}
}
=======================================================================================
// 관심사가 분리된 코드
// 이름을 입력받는 역할 담당
class InputManager {
func enterName(_ name: String) -> String {
// 사용자 이름 입력
let userName = name
return userName
}
}
// 이름을 출력하는 역할 담당
class OutputManager {
func printName(_ name: String) {
// 사용자 이름 출력
print("Hello, \(name)!")
}
}
// NameSettingController는 두 Manager를 이용하여 입력받고 출력하는 역할을 담당
// 이렇게 각 클래스가 자신의 관심사에만 집중하도록 하면, 코드의 가독성과 유지보수성이 향상된다. ⭐️⭐️
class NameSettingController {
let inputManager = InputManager()
let outputManager = OutputManager()
func enterName() {
let userName = inputManager.enterName()
outputManager.printName(userName)
}
}