[CS] 1주차 - 디자인 패턴

오늘·2022년 6월 22일
0
post-thumbnail
post-custom-banner

💻디자인 패턴


  • 라이브러리 vs 프레임워크
    • 공통점 : 공통으로 사용될 수 있는 특정한 기능을 모듈화한 것
    • 차이점
      • 라이브러리 : 폴더명, 파일명 등에 대한 규칙이 없음. 프레임워크에 비해 자유로움.
      • 프레임워크 : 폴더명, 파일명 등에 대한 규칙이 있음. 라이브러리에 비해 엄격함.
    • 프레임워크이고, 그 안에서 재사용이 가능하도록 만들어진 도구라이브러리임.

정의

프로그램을 설계할 때 발생했던 문제점들을 객체간의 상호관계 등을 이용하여 해결할 수 있도록 하나의 ‘규약’ 형태로 만들어 놓은 것.

💡 디자인 패턴은 문제점을 해결하기 위한 규약이다.

☝🏻 싱글톤 패턴(Singleton Pattern)

정의

하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴.

  • 데이터베이스의 연결 모듈

장점

  • 인스턴스 하나를 공유해서 사용하므로 인스턴스 생성 비용이 줄어 듦.

단점

  • 의존성이 높아짐.
  • TDD(Test-Driven Development)에서 단위 테스트(Unit Test)를 할 때 인스턴스를 공유함으로 인해 각 테스트마다 독립적인 테스트를 만들기가 어렵다.
  • 의존성 주입(DI, Dependency Injection)
    • 의존성

      ‘A가 B에 의존성이 있다’ → B의 변경사항에 대해 A 또한 변해야 한다.

    • 의존성 주입

      메인 모듈이 직접 하위 모듈에 대한 의존성을 주는 대신, 의존성 주입자(Dependency Injector)를 두어 메인 모듈이 간접적으로 의존성을 주입하는 방식

💡 의존성 주입을 사용하면 메인 모듈(상위 모듈)은 하위 모듈에 대한 의존성이 떨어진다.(디커플링 된다)

장점

  • 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅과 마이그레이션이 수월해짐.
  • 어플리케이션 의존성 방향이 일관되고, 어플리케이션을 쉽게 추론할 수 있으며, 모듈 간의 관계들이 조금 더 명확해짐.

단점

  • 모듈들이 더 분리되어 클래스 수가 증가
    → 복잡성 증가
  • 약간의 런타임 페널티가 생기기도 함.

의존성 주입의 원칙

  • 1) 상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 함.
  • 2) 둘 다 추상화에 의존해야 함. 추상화는 세부사항에 의존하지 말아야 함.

Kotlin으로 싱글톤 패턴 구현

object 키워드를 사용한다. Kolin은 object 키워드를 통해 언어 자체적으로 싱글톤 패턴을 지원한다.

object Singleton {
	val myVal = "싱글톤"
}

fun main() {
	println(Singleton.myVal)	// 싱글톤
}

Android의 싱글톤 패턴

  • RoomDatabase 클래스의 인스턴스는 app내에 하나만 존재해야 함. 이때 싱글톤 패턴을 사용.
  • MVVM architecture에서 Repository 클래스의 인스턴스는 앱 실행 중 하나만 필요. 이때 싱글톤 패턴을 사용.

🏭 팩토리 패턴(Factory Pattern)

정의

객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴.

  • 상속 관계에서 상위 클래스가 중요한 뼈대를 결정, 하위 클래스는 객체 생성에 관한 구체적인 내용을 결정.

장점

  • 상위 / 하위 클래스 분리로 느슨한 결합을 가짐.
  • 더 많은 유연성을 가짐
  • 객체 생성 로직의 분리로 유지 보수성 증가

Kotlin으로 팩토리 패턴 구현

enum classsealed class 를 이용해 효율적으로 팩토리 패턴을 구현할 수 있다.

enum class CoffeeType {
	AMERICANO, LATTE, MOCHA,
}

sealed class Coffee {
	object Americano: Coffee()
    object Latte: Coffee()
    object Mocha: Coffee()
}

object CoffeeFactory {

 	fun createCoffee(coffeeType: CoffeeType): Coffee {
    	return when(coffeeType) {
        	CoffeeType.AMERICANO -> Coffee.Americano
        	CoffeeType.LATTE -> Coffee.Latte
        	CoffeeType.MOCHA -> Coffee.Mocha
    	}
    }
 }

⚔️ 전략 패턴(Strategy Pattern)

또는 정책 패턴(Policy Pattern)

정의

객체의 행위를 바꾸고 싶은 경우 직접 수정하지 않고 전략(캡슐화된 알고리즘)을 컨택스트 안에서 바꿔주면서 상호 교체가 가능하게 만든 패턴

  • 컨텍스트(Context)
    → 상황, 맥락, 문맥
    개발자가 어떤 작업을 완료하는 데 필요한 모든 관련 정보

Kotlin으로 전략 패턴 구현

interface PaymentStrategy {
    fun pay()
}

class Cash: PaymentStrategy {
    override fun pay() {
        println("현금으로 결제")
    }
}

class CreditCard: PaymentStrategy {
    override fun pay() {
        println("신용 카드로 결제")
    }
}

class CheckoutCounter {
    fun pay(paymentStrategy: PaymentStrategy) {
        paymentStrategy.pay()
    }
}

fun main() {
    val checkoutCounter = CheckoutCounter()
    checkoutCounter.pay(CreditCard())	// 신용 카드로 결제
}

🔭 옵저버 패턴(Observer Pattern)

정의

주체객체상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 패턴

  • 주체
    객체의 상태 변화를 보고 있는 관찰자

  • 옵저버
    객체의 상태 변화에 따라 '추가 변화 사항'이 생기는 객체

  • 이벤트 기반 시스템
  • MVC 패턴

Kotlin으로 옵저버 패턴 구현

Delegates.observable()을 통해 간단한 옵저버 패턴을 구현할 수 있다.

import kotlin.properties.Delegates

var subjectMsg: String by Delegates.observable("") { property, oldValue, newValue ->
    println("${property.name} : $oldValue -> $newValue")
}

fun main() {
    subjectMsg = "안녕하세요"	// subjectMsg :  -> 안녕하세요
    subjectMsg = "반가워요"		// subjectMSg : 안녕하세요 -> 반가워요
}

Android의 옵저버 패턴

  • LiveData를 사용하면 데이터가 변경될 때 옵저버가 UI를 대신 업데이트 함.

🛡️ 프록시 패턴(Proxy Pattern)

정의

대상 객체에 접근하는 흐름을 가로채 대상 객체의 인터페이스 역할을 하는 패턴

  • 객체의 속성, 변환 등을 보완
  • 보안, 데이터 검증, 캐싱, 로깅에 사용

Kotlin으로 프록시 패턴 구현

ProtectedUserUser에 대한 프록시 역할을 해서 id""일 땐 회원가입이 되지 않도록 한다.

interface Account {
    fun register(id: String)
}

class User: Account {
    override fun register(id: String) {
        println("회원가입 성공 -> id: $id")
    }
}

class ProtectedUser(val user: User): Account {
    override fun register(id: String) = if (id == "") {
        println("이 아이디는 사용할 수 없습니다.")
    } else {
        println("사용 가능한 아이디로 회원가입 -> id: $id")
    }
}

fun main() {
    val user = ProtectedUser(User())
    user.register("")		// 이 아이디는 사용할 수 없습니다.
    user.register("oneul")	// 사용 가능한 아이디로 회원가입 -> id: oneul
}

Android의 프록시 패턴

  • Retrofit 클래스의 create 메소드

🎡 이터레이터 패턴(Iterator Pattern)

정의

이터레이터(iterator)를 사용하여 컬렉션(collection)의 요소들에 접근하는 패턴

장점

  • 컬렉션의 종류에 상관 없이 하나의 이터레이터로 순회 가능

Kotlin으로 이터레이터 패턴 구현

list_set_은 다른 자료형이지만, iteration 함수에서 같은 이터레이터를 사용하여 순회할 수 있다.

val list_: List<Int> = listOf(1, 2, 3, 4)
val set_: Set<Int> = setOf(5, 6, 7, 8)

fun iteration(iterable: Iterable<Int>) {
    iterable.forEach { print("$it ") }
    println()
}

fun main() {
    iteration(list_)
    iteration(set_)
}
  • 이터레이터 프로토콜
    • 이터러블한 객체들을 순회할 때 쓰이는 규칙
  • 이터러블한 객체
    • 반복 가능한 객체로 배열을 일반화한 객체

🔒 노출모듈 패턴(Revealing Module Pattern)

정의

즉시 실행 함수를 통해 private, public 같은 접근 제어자를 만드는 패턴

  • 접근 제어자가 없는 Javascript 같은 언어에서 접근 제어자 구현에 사용.

🎮 MVC 패턴

정의

어플리케이션의 구성 요소를 모델(Model), 뷰(Veiw), 컨트롤러(Controller)의 세 가지 역할로 구분한 패턴.

  • 모델
    • 어플리케이션의 데이터.
    • 데이터베이스, 상수, 변수 등을 의미.
    • 뷰에서 데이터를 생성 및 수정하면 컨트롤러를 통해 모델을 생성 및 갱신함.
    • 사용자 인터페이스 요소.
    • 모델을 기반으로 사용자가 볼 수 있는 화면.
    • 모델이 가지고 있는 정보를 따로 저장하지 않고 단순히 화면에 표시하는 정보만 가지고 있어야 함.
    • 변경이 일어나면 컨트롤러에 전달.
  • 컨트롤러
    • 이벤트 등 메인 로직을 담당.
    • 하나 이상의 뷰와 하나 이상의 모델을 연결함.
    • 모델과 뷰의 생명주기를 관리.
    • 모델이나 뷰의 변경 통지를 받으면 각 구성요소에 변경 내용에 대해 전달.

장점

  • 재사용성과 확장성이 용이함.

단점

  • 어플리케이션이 복잡해질수록 모델과 뷰의 관계가 복잡해짐.

🎞️ MVP 패턴

정의

MVC 패턴의 C가 프레젠터(presenter)로 교체된 패턴

  • 뷰와 프레젠터는 일대일 관계
    -> MVC보다 더 강한 결합을 지님.

🖼️ MVVM 패턴

정의

MVC 패턴의 C가 뷰모델(Veiw Model)로 교체된 패턴

  • 뷰모델
    • 뷰를 더 추상화한 계층.

특징

커맨드와 바인딩을 가짐.

  • 커맨드

    • 여러 가지 요소에 대한 처리를 하나의 액션으로 처리할 수 있게 하는 기법.
  • 데이터 바인딩

    • 화면에 보이는 데이터와 웹 브라우저의 메모리 데이터를 일치시키는 기법.
    • 뷰모델을 변경하면 뷰가 변경됨.

장점

  • 뷰와 뷰모델 사이의 양방향 데이터 바인딩을 지원.
  • UI를 별도의 코드 수정 없이 재 사용할 수 있음.
  • 단위 테스팅이 쉬움.

Android의 MVVM 패턴

  • Activity/Fragment를 View, LiveData를 ViewModel, RoomDatabase를 Model로 하는 MVVM 패턴 (현재는 권장 아키텍쳐 변경됨)

참고

profile
Junior Mobile 개발자
post-custom-banner

0개의 댓글