feat : SOLID - LSP 샘플 코드 구현
This commit is contained in:
@@ -28,6 +28,15 @@
|
|||||||
- 쿠폰 결제방식을 추가한다고 가정한다.
|
- 쿠폰 결제방식을 추가한다고 가정한다.
|
||||||
- 쿠폰으로 결제할 경우 잔고가 차감되지 않는다.
|
- 쿠폰으로 결제할 경우 잔고가 차감되지 않는다.
|
||||||
|
|
||||||
|
### LSP(Liskov Substitution Principle)
|
||||||
|
|
||||||
|
- 리스코프 치환 원칙
|
||||||
|
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
|
||||||
|
|
||||||
|
#### 구현 요구사항
|
||||||
|
|
||||||
|
- 좌표를 입력하면 해당 좌표로 이동수단의 위치가 변한다.
|
||||||
|
|
||||||
## 참고자료
|
## 참고자료
|
||||||
|
|
||||||
- [SOLID (객체 지향 설계)](https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84))
|
- [SOLID (객체 지향 설계)](https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84))
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.after
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleRepository
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class CarVehicleServiceAfter(
|
||||||
|
private val vehicleRepository: VehicleRepository
|
||||||
|
): VehicleServiceAfter() {
|
||||||
|
override fun move(request: VehicleMoveRequest): Vehicle {
|
||||||
|
println("자동차가 이동합니다.")
|
||||||
|
val vehicle = vehicleRepository.getVehicle(request.vehicleId)
|
||||||
|
vehicle.positionX = request.positionX
|
||||||
|
vehicle.positionY = request.positionY
|
||||||
|
return vehicle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun vehicleType(): VehicleType {
|
||||||
|
return VehicleType.CAR
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.after
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleRepository
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class PlaneVehicleServiceAfter(
|
||||||
|
private val vehicleRepository: VehicleRepository
|
||||||
|
): VehicleServiceAfter() {
|
||||||
|
override fun move(request: VehicleMoveRequest): Vehicle {
|
||||||
|
println("비행기가 이동합니다.")
|
||||||
|
val vehicle = vehicleRepository.getVehicle(request.vehicleId)
|
||||||
|
vehicle.positionX = request.positionX
|
||||||
|
vehicle.positionY = request.positionY
|
||||||
|
return vehicle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun vehicleType(): VehicleType {
|
||||||
|
return VehicleType.PLANE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.after
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import org.springframework.web.bind.annotation.PatchMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RequestMapping("/vehicles")
|
||||||
|
@RestController
|
||||||
|
class VehicleControllerAfter(
|
||||||
|
private val vehicleServiceFactoryAfter: VehicleServiceFactoryAfter
|
||||||
|
) {
|
||||||
|
@PatchMapping("/with-lsp")
|
||||||
|
fun move(@RequestBody request: VehicleMoveRequest): Vehicle {
|
||||||
|
val vehicleServiceAfter = vehicleServiceFactoryAfter.getVehicleServiceAfter(request.vehicleType)
|
||||||
|
return vehicleServiceAfter.move(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.after
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
|
||||||
|
abstract class VehicleServiceAfter {
|
||||||
|
abstract fun move(request: VehicleMoveRequest): Vehicle
|
||||||
|
|
||||||
|
abstract fun vehicleType(): VehicleType
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.after
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class VehicleServiceFactoryAfter(
|
||||||
|
val vehicleServiceAfters: List<VehicleServiceAfter>
|
||||||
|
) {
|
||||||
|
fun getVehicleServiceAfter(vehicleType: VehicleType): VehicleServiceAfter {
|
||||||
|
return vehicleServiceAfters.find { it.vehicleType() == vehicleType }
|
||||||
|
?: throw NoSuchElementException("해당 이동수단에 대한 구현이 존재하지 않습니다.")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.before
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleRepository
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class CarVehicleServiceBefore(
|
||||||
|
private val vehicleRepository: VehicleRepository
|
||||||
|
) : VehicleServiceBefore(vehicleRepository) {
|
||||||
|
override fun move(request: VehicleMoveRequest): Vehicle {
|
||||||
|
val vehicle = vehicleRepository.getVehicle(request.vehicleId)
|
||||||
|
vehicle.positionX += request.positionX // 하위 타입에서의 잘못된 오버라이딩!
|
||||||
|
vehicle.positionY += request.positionY // 하위 타입에서의 잘못된 오버라이딩!
|
||||||
|
return vehicle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun vehicleType(): VehicleType {
|
||||||
|
return VehicleType.CAR
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.before
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleRepository
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class PlaneVehicleServiceBefore(
|
||||||
|
private val vehicleRepository: VehicleRepository
|
||||||
|
) : VehicleServiceBefore(vehicleRepository) {
|
||||||
|
override fun move(request: VehicleMoveRequest): Vehicle {
|
||||||
|
val vehicle = vehicleRepository.getVehicle(request.vehicleId)
|
||||||
|
vehicle.positionX -= request.positionX // 하위 타입에서의 잘못된 오버라이딩!
|
||||||
|
vehicle.positionY -= request.positionY // 하위 타입에서의 잘못된 오버라이딩!
|
||||||
|
return vehicle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun vehicleType(): VehicleType {
|
||||||
|
return VehicleType.PLANE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.before
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import org.springframework.web.bind.annotation.PatchMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RequestMapping("/vehicles")
|
||||||
|
@RestController
|
||||||
|
class VehicleControllerBefore(
|
||||||
|
private val vehicleServiceFactoryBefore: VehicleServiceFactoryBefore
|
||||||
|
) {
|
||||||
|
@PatchMapping("/none-lsp")
|
||||||
|
fun move(@RequestBody request: VehicleMoveRequest): Vehicle {
|
||||||
|
val vehicleServiceBefore = vehicleServiceFactoryBefore.getVehicleServiceBefore(request.vehicleType)
|
||||||
|
return vehicleServiceBefore.move(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.before
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.Vehicle
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleMoveRequest
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleRepository
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
|
||||||
|
abstract class VehicleServiceBefore(
|
||||||
|
private val vehicleRepository: VehicleRepository
|
||||||
|
) {
|
||||||
|
open fun move(request: VehicleMoveRequest): Vehicle {
|
||||||
|
val vehicle = vehicleRepository.getVehicle(request.vehicleId)
|
||||||
|
vehicle.positionX = request.positionX
|
||||||
|
vehicle.positionY = request.positionY
|
||||||
|
return vehicle
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun vehicleType(): VehicleType
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.before
|
||||||
|
|
||||||
|
import com.banjjoknim.soliddesignpatternsample.solid.lsp.common.VehicleType
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class VehicleServiceFactoryBefore(
|
||||||
|
val vehicleServiceBefores: List<VehicleServiceBefore>
|
||||||
|
) {
|
||||||
|
fun getVehicleServiceBefore(vehicleType: VehicleType): VehicleServiceBefore {
|
||||||
|
return vehicleServiceBefores.find { it.vehicleType() == vehicleType }
|
||||||
|
?: throw NoSuchElementException("해당 이동수단에 대한 구현이 존재하지 않습니다.")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
|
||||||
|
|
||||||
|
import javax.persistence.Entity
|
||||||
|
import javax.persistence.Id
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class Vehicle(
|
||||||
|
var positionX: Int = 0,
|
||||||
|
var positionY: Int = 0,
|
||||||
|
@Id
|
||||||
|
val id: Long = 0L
|
||||||
|
)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
|
||||||
|
|
||||||
|
data class VehicleMoveRequest(
|
||||||
|
val vehicleId: Long,
|
||||||
|
val positionX: Int,
|
||||||
|
val positionY: Int,
|
||||||
|
val vehicleType: VehicleType
|
||||||
|
)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
|
||||||
|
|
||||||
|
interface VehicleRepository {
|
||||||
|
fun getVehicle(vehicleId: Long): Vehicle
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
class VehicleRepositoryStub : VehicleRepository {
|
||||||
|
override fun getVehicle(vehicleId: Long): Vehicle {
|
||||||
|
return Vehicle(id = vehicleId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
|
||||||
|
|
||||||
|
enum class VehicleType {
|
||||||
|
CAR,
|
||||||
|
PLANE
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user