Factory Method Pattern

Seungjae·2022년 4월 8일
0

디자인 패턴 공부

목록 보기
1/4

슈퍼클래스에서 객체를 생성하기 위한 인터페이스를 제공하고 서브클래스가 생성될 객체의 유형을 변경할 수 있도록 하는 디자인 패턴이다. 일반적으로 슈퍼클래스에서 어떠한 비즈니스 로직이 존재하고, 그 로직을 수행하는 객체를 생성하는 것을 서브클래스에서 구현하는 형태이다.

Problem


물류 관리 응용 프로그램을 만들었다. 앱의 첫 번째 버전은 트럭 운송만 처리할 수 있으므로 대부분의 코드는 Truck클래스 내에 있다. 나중에 사업을 확장하며 해상 물류에 대해서도 서비스를 확장해야할 시기가 왔다. 하지만 현재 대부분의 코드는 다 Truck 클래스와 연결되어있다. 지금 전체적으로 Ship클래스를 추가하여 변경한다고 하더라도 나중에 또 다른 운송 수단에 대해서 확장된다면? 문제가 복잡해지고 사이드 이펙트가 커질 수 있다.

Solve


직접적인 객체 생성 호출을 팩토리 메서드 내에서 해결한다. 이때 반환되는 객체를 제품이라고 한다. 팩토리 메서드를 가지고 있는 객체를 상속하여 자신이 원하는 제품을 만들도록 할 수 있다. 이 때 제품은 해당 도메인 내에서 정의된 동작을 하기위해 인터페이스를 구현해야한다.

클라이언트는 모든 제품을 추상적으로 취급할 수 있고, 그저 인터페이스를 사용할 뿐이다. 클라이언트는 내부적으로 어떤 일이 일어나는지 알 필요가 없다. 그저 필요한 기능을 호출할 뿐이다. 이렇게 팩토리 클래스, 제품 클래스를 추상화함으로써 더 유연한 서비스를 만들 수 있다. 운송 수단이 추가되면 기존 코드를 변경하는 것이 아닌 해당하는 클래스를 추가만 하면 된다. 이것은 "Append Only", 즉 OCP를 잘 지켰다.

Code


Logistics

package factory_method

abstract class Logistics {
  fun planDelivery() {
    val transport = createTransport()
    println("---Start Delivery---")
    transport.deliver()
    println("---End Delivery---")
  }

  abstract fun createTransport(): Transport
}

RoadLogistics

package factory_method

class RoadLogistics : Logistics() {
  override fun createTransport(): Transport = Truck()
}

SeaLogistics

package factory_method

class SeaLogistics : Logistics() {
  override fun createTransport(): Transport = Ship()
}

Transport

package factory_method

interface Transport {
  fun deliver()
}

Truck

package factory_method

class Truck : Transport {
  override fun deliver() {
    println("Go Go Truck!")
  }
}

Ship

package factory_method

class Ship : Transport {
  override fun deliver() {
    println("Go Go Ship!")
  }
}

Main

package factory_method


fun main() {
  println("What mode of transport would you like to use?")
  println("1. Truck")
  println("2. Ship")

  val logistics: Logistics = when(readLine()) {
    "1" -> RoadLogistics()
    "2" -> SeaLogistics()
    else -> {
      println("Error!")
      return
    }
  }

  logistics.planDelivery()
}

구조


적용가능성


  • 코드에서 작업해야 하는 객체의 정확한 유형과 종속성을 미리 모르는 경우
  • 라이브러리나 프레임워크의 사용자에게 내부 구성 요소를 확장하는 방법을 제공하려는 경우
  • 매번 재구축하는 대신 기존 개체를 재사용하여 시스템 리소스를 절약하려는 경우

장점﹒단점


장점

  • 제작자와 구체적인 제품 간의 긴밀한 결합을 피할 수 있다.
  • SRP => 제품 생성 책임을 프로그램의 한 위치로 이동
  • OCP => 기존 클라이언트 코드를 손상시키지 않고 새로운 유형의 제품을 프로그램에 도입할 수 있다.

단점

  • 패턴을 구현하기 위해 많은 새 하위 클래스를 도입해야 하므로 코드가 더 복잡해질 수 있다. 가장 좋은 시나리오는 생성자 클래스의 기존 계층 구조에 패턴을 도입하는 경우이다.

Git


https://github.com/oh980225/DesignPattern/tree/main/src/main/kotlin/factory_method

Ref


https://refactoring.guru/design-patterns/factory-method

profile
코드 품질의 중요성을 아는 개발자 👋🏻

0개의 댓글