Junuuu 2023. 4. 21. 00:01
반응형

스프링은 객체 지향의 특성과 설계 원칙을 극한까지 적용한 프레임워크입니다.

스프링을 공부하다 보면 자연스럽게 객체 지향 설계의 베스트 프렉티스, 즉 디자인 패턴을 만날 수 있습니다.

 

어댑터 패턴

호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴입니다.

serviceA.runServiceA()
serviceB.runServiceB()


//위의 코드를 어댑터로 감싼다

class AdapterServiceA{
	val sa1= ServiceA()
    
	fun runService(){
		sa1.runServiceA()
	}
}

class AdapterServiceB{
	val sb1= ServiceB()
    
	fun runService(){
		sb1.runServiceB()
	}
}

// 이제 다음과 같이 같은 이름으로 호출할 수 있습니다.

AdaterServiceA.runService()
AdaterServiceB.runService()

인터페이스를 활용하여 더 개선시킬 수 있습니다.

 

프록시 패턴과 데코레이터 패턴의 차이

둘은 유사하지만 다음과 같이 다르다

  • 데코레이터 패턴은 메서드 호출의 반환값에 변화를 준다. (반환값에 장식을 더함)
  • 프록시 패턴은 제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 둔다 (별도의 추가적인 로직 처리 목적)

 

싱글톤 패턴

  • 클래스 인스턴스, 즉 객체를 하나만 만들어 사용하는 패턴

 

템플릿 메서드 패턴

class Dog{
	fun playWithOnwer(){
		println("duplicate1")
		println("멍멍") -> play()
		println("duplicate2")
		println("duplicate3")
	}
}

class Cat{
	fun playWithOnwer(){
		println("duplicate1")
		println("야옹") // -> play()
		println("duplicate2")
		println("duplicate3")
	}
}

//멍멍과 야옹빼고는 동일하다

//Animal이라는 추상클래스에 play()라는 추상메서드를 활용하여 중복되지 않은 부분을 구현하도록 한다.

val bolt: Animal = Dog()
val kitty: Animal = Cat()
bolt.playWithOnwer()
kitty.playWithOnwer()

상속과 추상메서드를 이용하여 상위 클래스의 견본 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴

 

팩토리 메서드 패턴

  • 오버라이딩된 메서드가 구현체의 객체를 반환하는 패턴

 

전략 패턴

interface Strategy{
    fun runStrategy()
}

class StrategyGun: Strategy{
    override fun runStrategy() {
        println("총을 쏜다")
    }
}

class StrategySword: Strategy{
    override fun runStrategy() {
        println("검을 휘두른다")
    }
}

class Soldier{
    fun runContext(strategy: Strategy){
        println("전투 시작")
        strategy.runStrategy()
        println("전투 종료")
    }
}

fun main() {
    val soldier = Soldier()
    soldier.runContext(StrategyGun())
    soldier.runContext(StrategySword())
}

클라이언트가 전략을 생성해 전략을 실행할 콘텍스트에 주입하는 패턴

 

템플릿 콜백 패턴

class Soldier{
    fun runContext(weapon: String){
        println("전투 시작")
        executeWeapon(weapon).runStrategy()
        println("전투 종료")
    }
    
    fun executeWeapon(weapon: String): Strategy{
        return object : Strategy {
            override fun runStrategy() {
                println(weapon)
            }
        }
    }
}

fun main() {
    val soldier = Soldier()
    soldier.runContext("총을 쏜다")
    soldier.runContext("칼을 휘두른다")
}

전략을 익명 내부 클래스로 구현한 전략 패턴