feat : SOLID - LSP 샘플 코드 구현

This commit is contained in:
banjjoknim
2022-11-09 14:45:35 +09:00
parent e9b76a0024
commit ddc3f84a5d
16 changed files with 242 additions and 0 deletions

View File

@@ -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))

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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("해당 이동수단에 대한 구현이 존재하지 않습니다.")
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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("해당 이동수단에 대한 구현이 존재하지 않습니다.")
}
}

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -0,0 +1,5 @@
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
interface VehicleRepository {
fun getVehicle(vehicleId: Long): Vehicle
}

View File

@@ -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)
}
}

View File

@@ -0,0 +1,6 @@
package com.banjjoknim.soliddesignpatternsample.solid.lsp.common
enum class VehicleType {
CAR,
PLANE
}