• 디자인 패턴이란 사실 자주 발생하는 문제에 대한 검증된 해결책이다

  • 생성 패턴

    • 언제, 어떻게 객체를 생성 할 지에 관한 디자인 패턴

    • 싱글톤 패턴

      • 시스템에 인스턴스가 하나만 존재해야 하고 모든 부분에서 접근해야 할 때 사용하는 패턴
      • example
        • 코틀린에서는 object는 생성자를 가질 수 없어 Init 블록으로 초기화해야 한다
        • object singleton { ... }
    • 팩토리 메서드 패턴

      • 객체를 생성하는 매서드에 관한 패턴
      • 생성자만으로 한계가 있는 객체 생성 시에 사용하는 패턴
      • example
        • interface Car class SportCar: car class NomarlCar: car fun factory(type): Car { return when(type) { "sport" -> SportCar() "normal" -> NormalCar() else -> throw Excpetion() } }
    • 정적 팩토리 메서드

      • 생성자에서 예외를 발생시켜야 하거나 생성자가 많아 명시적인 이름이 필요할 때 사용하는 패턴
      • 캐싱 또는 하위 클래스를 생성해야 할 경우 유리하다
      • example
        • class Server(port: Long) { companion object { fun withPort(port: Long) = Server(port) } }
    • 추상 팩토리

      • 여러 팩토리 메서드를 감싸는 팩토리 패턴 → 팩토리를 만들어 내는 팩토리
      • 어떤 객체의 집합을 한꺼번에 교체하면서 만들어야 하는 경우 사용
      • example
        • class SportEngine class SportMission class NormalEngine class NormalMission fun factory(type): Car { return when(type) { "sport" -> SportCar(SportEngine(), SportMission()) "normal" -> NormalCar(NormalEngine(), NormalMission()) else -> throw Excpetion() } }
    • 빌더 패턴

      • 복잡한 객체를 보다 쉽게 만들 수 있게 하기 위한 패턴
      • example
        • 코틀린에서는 fluent setter 을 이용하여 코드를 더 간결하게 만들 수 있다
        • 이는 생성자, 함수에 기본 값을 설정하여 필요한 값만 받도록 하기 위함이다
        • class mail( val to: List<String>, val cc: List<String> = emptyListOf(), val title: String = "" )
    • 프로토타입 패턴

      • 유사하면서도 조금씩 서로 다른 객체를 그때그때 목적에 맞게 생성하기 위해 사용되는 패턴
      • 필요한 필드만 설정하여 불필요한 나머지 필드 설정을 제거
      • example
        • data class User(val a: String, val b: String) // b is new field val userList: MutableList<User> fun addNewUser(oldUser: User, b: String) { userList.add(oldUser.copy(b = b)) }
  • 구조 패턴

    • 객체 간의 관계를 다루는 디자인 패턴

    • 데코레이터 패턴

      • 속성이 아닌 동작이 조금씩 다른 클래스를 만들 때 사용하는 패턴
      • 기존 기능에서 조금씩 변형된 동작을 추가할 수 있다
      • example
        • interface Ifce class Default: Ifce class AddOn1(privat val impl: Ifce): Ifce by impl class AddOn2(privat val impl: Ifce): Ifce by impl --- use val default = Default() val addOn1 = AddOn1(default) val addOn2 = AddOn2(addOn2)
    • 어댑터 패턴

      • 어떤 인터페이스를 다른 인터페이스로 변환하고자 할 때 사용하는 패턴
      • 코틀린에서는 확장함수를 이용하여 클래스를 생성하지 않고 구현 가능하다
    • 브릿지 패턴

      • 상속을 남용하는 것을 막기 위한 패턴
      • 해당 공통 기능을 직접 구현하는 대신 의존성 주입을 통해 구현
      • example
        • interface Weapon interface Shied class Soldier(w: Weapon, s: Shied) val normalSoldier = Soldier(normalWeapon, normalShied) val fireSoldier = Soldier(fireWeapon, normalShied) val Shieder = Soldier(normalWeapon, TopShied)
    • 합성 패턴

      • 동일한 행동을 하는 여러 집합을 다루기 위한 패턴

      • 코틀린에서는 상속과 vararg를 이용하여 쉽게 구현

      • example

        interface Soldier
        
        class NormalSoldier: Soldier
        
        class Squad(val list: List<Soldier>): Soldier {
          constructor(vararg units: Soldier) = list = units.toList()
        }
        
    • 퍼사드 패턴

      • 지저분한 구현 세부 사항을 모아서 감추는 패턴
      • 여러 클래스를 주입받은 단일 클래스 또는 확장함수를 이용하여 구현
    • 경량(flyweight) 패턴

      • 상태를 갖지 않는 객체를 이용하는 패턴
      • 무거운 객체를 제한적으로 생성하고(싱글턴 등으로) 경량 객체들이 무거운 객체를 공유하여 사용하는 패턴
    • 프록시 패턴

      • 객체의 기능을 확장하는 패턴이지만 데코레이터와 달리 원래 동작을 아예 수행하지 않을 수 있는 패턴
      • 기존 객체를 감싸는 새로운 객체를 생성하여 이 객체를 사용자가 호출하도록 만들어서 수행
  • 동작 패턴

    • 객체 간의 상호 작용에 관한 디자인 패턴
    • 전략 패턴
      • 객체의 동작을 런타임에 변경하는 패턴
      • 인터페이스를 이용하여 런타임에 구현체를 변경하는 방식으로 동작
      • 코틀린에서는 교체해야 하는 알고리즘이 상태에 의존하지 않는다면 함수 인자로 받아 구현이 가능하다
    • 반복자(iterator) 패턴
      • 복잡한 자료 구조를 단순한 리스트 형태로 평면화하기 위한 패턴
      • 코틀린에서는 Iterator<T> 인터페이스를 구현하여 사용한다
    • 상태 패턴
      • 전략 패턴과 달리 외부가 아닌 입력을 통한 내부 변경을 하기 위한 패턴 → 상태 변경을 통제하게 두기 위해 사용
      • 해당 상태 자체를 클래스로 정의하고 변경할 맥락 객체(대상 상태를 가진)를 입력으로 받아 동작을 수행한다
      • example
    • 명령 패턴
    • 책임 사슬 패턴
    • 중개인(Mediator) 패턴
    • 기억(Memento) 패턴
    • 방문자 패턴
    • 템플릿 메서드 패턴
    • 관찰자 패턴
  • 함수형 프로그래밍

  • 반응형 프로그래밍과 코루틴

  • 동시성 디자인 패턴


  • 인터페이스와 추상 클래스의 차이점은 상태를 가진다는 점이다
  • 문(statement): 아무것도 반환하지 않는 코드 블록
  • 식(expression): 새로운 값을 반환하는 코드 블록
  • 코틀린에서는 Mutex.withLock {} 같은 신택스 슈거를 이용해 락 해제를 쉽게 할 수 있다
  • 코틀린에서 상태와 함께 어떤 데이터를 관리해야하는 경우 열거형보다 봉인 클래스가 훨씬 유용하다