시배's Android
Kotlin | Kotlin design patterns with code example 본문
Singleton
"싱글톤 패턴"은 클래스가 하나의 인스턴스만 가지고 있도록 보장하며, 그 인스턴스에 대한 전역 접근점을 제공합니다.
object SingletonExample {
fun doSomething() {
println("Singleton : Doing something")
}
}
// Usage
SingletonExample.doSomething()
Decorator
"데코레이터 패턴"은 동일한 클래스에서 다른 객체의 동작을 동적으로 추가할 수 있게 해줍니다. 이 때 다른 객체들의 동작에 영향을 주지 않고 개별 객체에 동작을 추가할 수 있습니다.
interface ChrismasTree {
fun decorate() : String
}
class PineChrismasTree : ChrismasTree {
override fun decorate() : String {
return "Decorating pine tree"
}
}
class Garlands(private val tree : ChrismasTree) : ChrismasTree by tree {
override fun decorate() : String {
return tree.decorate() + decorateWithGarlands()
}
private fun decorateWithGarlands() : String {
return " with Garlands"
}
}
fun main() {
val chrismasTree = Garlands(PineChrismasTree())
val decorateChrismasTree = chrismasTree.decorate()
println(decorateChrismasTree)
}
Factory
클래스 기반 프로그래밍에서의 "팩토리 메서드 패턴"은 정확한 클래스를 지정하지 않고 객체를 생성하기 위해 팩토리 메서드를 사용합니다. 생성자를 호출하는 대신, 객체는 인터페이스나 기본 클래스 내에서 팩토리 메서드를 호출하여 생성됩니다. 이 팩토리 메서드는 파생 클래스에 의해 선택적으로 구현될 수 있습니다.
interface Product {
fun create()
}
class ConcreteProductA : Product {
override fun create() = println("Product A created")
}
class ConcreteProductB : Product {
override fun create() = println("Product B created")
}
class ProductFactory {
fun createProduct(type : String) : Prdocut =
when(type){
"A" -> ConcreteProductA()
"B" -> ConcreteProductB()
else -> throw IllegalArgumentException("Invalid product type")
}
}
// Usage
val facotry = ProductFactory()
val productA = factory.createProduct("A")
productA.create()
val productB = factory.createProduct("B")
productB.create()
Adapter
"어댑터 패턴"은 호환되지 않는 인터페이스를 가진 객체들이 함께 작동할 수 있도록 하기 위해 한 인터페이스를 다른 인터페이스로 변환하는 래퍼를 제공합니다.
interface NewPaymentProcessor {
fun pay(amount : Double)
}
class OldPaymentProcessor {
fun makePayment(price : Int){
println("Payment made : $price")
}
}
class Adapter(
private val oldPaymentProcessor : OldPaymentProcessor
) : NewPaymentProcessor {
override fun pay(amount : Double) {
oldPaymentProcessor.makePayment(amount.toInt())
}
}
// Usage
val newPaymentProcessor : NewPaymentProcessor = Adapter(OldPaymentProcessor())
newPaymentProcessor.pay(49.99)
Observer
"옵저버 패턴"은 객체 간의 종속성을 정의하여 하나의 객체의 상태가 변경될 때, 해당 객체의 모든 종속 객체들이 자동으로 알림을 받고 업데이트되는 패턴입니다.
interface observer {
fun update(message : String)
}
class ConcreteObserver(private val name : String) : Observer {
override fun update(message : String) = println("$name received $message")
}
class Subject {
private val observers = mutableListOf<Observer>()
fun addObserver(observer : Observer) = observers.add(observer)
fun removeObserver(observer : Observer) = observers.remove(observer)
fun notifyObservers(message : String) {
for(observer in observers){
observer.update(message)
}
}
}
// Usage
val subject = Subject()
ConcreteObserver("Observer 1").apply { subject.addObserver(this) }
ConcreteObserver("Observer 2").apply { subject.addObserver(this) }
subject.notifyObservers("Hello observers!")
Facade
"파사드 패턴"은 전체 클래스 시스템에 대한 단순화된 인터페이스를 제공하여 사용을 더 쉽게 만드는 패턴입니다.
class SubsystemA {
fun operationA() {
println("Subsystem A : Operation A")
}
}
class SubsystemB {
fun operationB() {
println("Subsystem B : Operation B")
}
}
class Facade(
private val subsystemA : SubsystemA,
private val subsystemB : SubsystemB
) {
fun doSomething() {
subsystemA.operationA()
subsystemB.operationB()
}
}
// Usage
val subsystemA = SubsystemA()
val subsystemB = SubsystemB()
val facade = Facade(subsystemA, subsystemB)
facade.doSomething()
Proxy
"프록시 패턴"은 다른 객체에 대한 접근을 제어하거나 기능을 추가하거나 인스턴스화를 지연시키기 위한 대리자 역할을 하는 객체를 제공하는 패턴입니다.
interface Internet {
fun connectTo(serverHost : String)
}
class RealInternet : Internet {
override fun connectTo(serverHost : String) {
println("Connected to $serverHost")
}
}
class ProxyInternet(private val realInternet : RealInternet) : Internet {
override fun connectTo(serverHost : String){
if(serverHost == "example.com"){
println("Access denied. Cannot connect to $serverHost")
}else {
realInternet.connectTo(serverHost)
}
}
}
// Usage
val realInternet = RealInternet()
val proxyInternet = ProxyInternet(realInternet)
// Output : Access denied. Cannot connect to example.com
proxyInternet.connectTo("example.com")
// Output : Connected to google.com
proxyInternet.connectTo("google.com")
Strategy
"전략 패턴"은 알고리즘군을 정의하고 각각을 캡슐화하여 서로 교환 가능하도록 만드는 디자인 패턴으로, 실행 중에 알고리즘을 선택할 수 있게 합니다.
interface PaymentStrategy{
fun pay(amount : Double)
}
class CreditCardPayment : PaymentStrategy {
override fun pay(amount : Double) {
println("Paid $amount using Credit Card.")
}
}
class PayPalPayment : PaymentStrategy {
override fun pay(amount : Double) {
println("Paid $amount using PayPal.")
}
}
class ShoppingCard(private val paymentStrategy : PaymentStrategy) {
fun checkout(amount : Double){
paymentStrategy.pay(amount)
}
}
// Usage
fun main() {
val cart = ShoppingCart(CreditCardPayment())
cart.checkout(100.0)
val anotherCart = ShoppingCart(PayPalPayment())
anotherCart.checkout(50.0)
}
Prototype
"프로토타입 패턴"은 기존 객체를 복사하여 새로운 객체를 생성하는 방식으로, 객체를 처음부터 생성하는 비용을 피할 수 있도록 하는 디자인 패턴입니다.
data class PrototypeProduct(val name : String)
fun main(){
val oridinalProduct = PrototypeProduct("Original Product")
val clonedProduct = originalProduct.copy()
println(originalProduct)
println(clonedProduct)
}
'Kotlin > Kotlin' 카테고리의 다른 글
Kotlin | The Big Difference Between Flows and Channels in Kotlin (0) | 2023.09.20 |
---|---|
Kotlin | KSP vs KAPS (0) | 2023.09.20 |
Kotlin | Deep Dive into Sealed Interfalces (0) | 2023.09.03 |
Kotlin | Generic (0) | 2023.08.27 |
Kotlin | Flow 마스터하기 (0) | 2023.08.13 |