Я написал сложный класс Kotlin Env, в котором мне нужно реализовать метод deepCopy. Вот минимальный репродуктивный пример класса и классов, на которые он ссылается:
@Serializable
data class OrderDetails(
val id: Long,
val name: String,
val type: ProductType,
@EncodeDefault val description: String = "",
@EncodeDefault var timeBuffer: Int = 0,
val operations: List,
@EncodeDefault var incomeTime: Int = 0,
@EncodeDefault val plannedDeliveryTime: Int = 0,
@EncodeDefault var actualDeliveryTime: Int = 0,
@EncodeDefault var releaseTime: Int = 0,
@EncodeDefault var shopCapacity: Int = 0,
@EncodeDefault var state: OrderState = OrderState.RESTRICTED
) {}
@Serializable
class Order(override val id: Long,
val productType: ProductType,
val deliveryTime: Int,
val incomeTime: Int = 0
) : AbstractAsset() {
override var name: String = "$productType-order-$id"
private var operations = getOperations(productType) // fixme - getters not included in serialization
private var orderDetails: OrderDetails = OrderDetails(
id = id,
type = productType,
name = name,
operations = operations,
plannedDeliveryTime = deliveryTime,
incomeTime = incomeTime
)
override val clientConfiguration: ClientConfiguration
get() = TODO("Not yet implemented")
fun getState(): OrderState {
return orderDetails.state
}
val details: OrderDetails get() = orderDetails
fun release(time: Int) {
if (orderDetails.state != OrderState.RESTRICTED) return
orderDetails.state = OrderState.PROCESSING
orderDetails.releaseTime = time
}
fun updateOrder(time: Int) {
when (orderDetails.state) {
OrderState.RESTRICTED -> {
updateDeliveryTimeBuffer(time)
logger.info { "Order $name is not released yet." }
}
OrderState.PROCESSING -> {
orderDetails.operations.filter { it.state == OperationState.RESTRICTED }.forEach { updateOperationState(it) }
if (orderDetails.operations.all { it.state == OperationState.DONE }) {
orderDetails.state = OrderState.DONE
orderDetails.actualDeliveryTime = time
orderDetails.timeBuffer = orderDetails.plannedDeliveryTime.minus(time)
logger.info { "Order $name is finished." }
}
else {
updateDeliveryTimeBuffer(time)
logger.info { "Order $name is in process." }
}
}
OrderState.DONE -> logger.info { "Order $name is finished." }
}
}
}
@Serializable
data class OperationDetails(
val id: Long,
val duration: Int,
val name: String,
val previous: List,
var cumulativeProcessTime: Int = 0,
var orderDetailsType: ProductType,
var orderDetailsName: String = "",
@EncodeDefault var assignee: Long? = null,
@EncodeDefault var startTime: Int? = null,
@EncodeDefault var timeBuffer: Int = 0,
@EncodeDefault var setupTime: Int = 0,
@EncodeDefault var remainingProcessTime: Int = duration,
@EncodeDefault var remainingSetupTime: Int = setupTime,
@EncodeDefault var plannedEndTime: Int = 0,
@EncodeDefault var actualEndTime: Int = 0,
@EncodeDefault var state: OperationState = OperationState.RESTRICTED,
@EncodeDefault var relTimeBuffer: Float = 0F,
@EncodeDefault val setupTimeMatrix: MutableMap
> = OrderSetupMatrix.setupTimeMatrix
) {}
@Serializable
class Operation(override val id: Long, override val name: String, val assetDetails: OperationDetails
) : AbstractAsset(){
override val clientConfiguration: ClientConfiguration
get() = TODO("Not yet implemented")
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Operation
if (id != other.id) return false
if (name != other.name) return false
if (assetDetails != other.assetDetails) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + assetDetails.hashCode()
return result
}
}
@Serializable
data class BreakdownEvent(
val workstationId: Long,
val startTime: Int,
var endTime: Int?
)
@Serializable
data class JobArrivalEvent(
val arrivalTime: Int,
val deliveryTime: Int,
val productType: ProductType,
)
Я уже пытался реализовать метод deepCopy, используя сериализацию Kotlinx для кодирования в json и последующего декодирования:
object SerializationUtil {
inline fun deepCopy(obj: T): T {
val json = Json
val jsonString = json.encodeToString(serializer(), obj)
return json.decodeFromString(serializer(), jsonString)
}
}
Я написал тестовый метод для сравнения двух объектов Env. Если я инициализирую экземпляр Env и использую метод deepCopy для копирования этого экземпляра, все свойства исходного и скопированного объектов будут аналогичны. Однако при использовании метода Env.step() с одинаковыми аргументами (который изменяет такие метрики, как состояние и временной буфер операций) в обоих экземплярах Env соответственно, свойства некоторых экземпляров Operation различаются. Как правильно скопировать объект Env? Что мне не хватает?
Я написал сложный класс Kotlin Env, в котором мне нужно реализовать метод deepCopy. Вот минимальный репродуктивный пример класса и классов, на которые он ссылается: [code]@Serializable class Env( override var time: Int, override var workstationPool: List, override var jobPool: MutableList, override val jobArrivalEvents: List, override val breakdownEvents: List , ) : AbstractEnvironment() {
override fun step(actionMap: Pair) : Triple { handleJobEvents() handleDisruptiveEvents()
for (workstation in workstationPool) { if (actionMap.second[workstation.id] != null) { workstation.allocateOperation(actionMap.second[workstation.id]!!, time) } workstation.process(time) }
val timeBufferList = mutableListOf() for (job in jobPool) { if (actionMap.first[job.id] == OrderAction.RELEASE && job.getState() == OrderState.RESTRICTED) { logger.info { "Releasing order ${job.name}" } job.release(time) } job.updateOrder(time)
fun deepCopy(): DiscreteSchedulingEnv { return deepCopy(this) }
} [/code] [code]@Serializable data class WorkstationDetails( val id: Long, val name: String, @EncodeDefault var state: WorkstationState = WorkstationState.IDLE, @EncodeDefault var workload: Int = 0, @EncodeDefault var numSetupChanges: Int = 0, @EncodeDefault var operationLog: MutableList = mutableListOf(), @EncodeDefault var downtime: Int = 0, @EncodeDefault val breakdownEvents: MutableList = mutableListOf() ) {}
@Serializable class Workstation(val assetDetails: WorkstationDetails): AbstractAsset() {
override val id: Long = assetDetails.id override val name: String = assetDetails.name
override val clientConfiguration: ClientConfiguration get() = TODO("Not yet implemented")
var state: WorkstationState get() = assetDetails.state private set(value) { assetDetails.state = value }
private var allocatedOperation: OperationDetails? = null
fun getAllocatedOperation(): OperationDetails?{ return allocatedOperation }
fun allocateOperation(operation: OperationDetails, time: Int) { if (state != WorkstationState.IDLE ) return
if (allocatedOperation == null) { allocatedOperation = operation allocatedOperation!!.startTime = time allocatedOperation!!.assignee = id val setupTime = operation.getSetupTimeForProductType(getProductTypeOfLastOperation()) allocatedOperation!!.setupTime = setupTime allocatedOperation!!.remainingSetupTime = setupTime if (getProductTypeOfLastOperation() != null){ if (getProductTypeOfLastOperation() != operation.orderDetailsType) assetDetails.numSetupChanges += 1 } else assetDetails.numSetupChanges += 1 allocatedOperation!!.plannedEndTime = time + allocatedOperation!!.setupTime + allocatedOperation!!.duration } }
fun process(time: Int) { when (state) { WorkstationState.IDLE -> processTaskAllocation() WorkstationState.PROCESSING -> handleTaskExecution(allocatedOperation!!, time) WorkstationState.FAILURE -> { assetDetails.downtime += 1 if (allocatedOperation != null) { logger.info { "Workstation $id can not process operation (ID / name) ${allocatedOperation!!.name} / ${allocatedOperation!!.name} due to an existing breakdown." } } } } }
} [/code] [code]@Serializable data class OrderDetails( val id: Long, val name: String, val type: ProductType, @EncodeDefault val description: String = "", @EncodeDefault var timeBuffer: Int = 0, val operations: List, @EncodeDefault var incomeTime: Int = 0, @EncodeDefault val plannedDeliveryTime: Int = 0, @EncodeDefault var actualDeliveryTime: Int = 0, @EncodeDefault var releaseTime: Int = 0, @EncodeDefault var shopCapacity: Int = 0, @EncodeDefault var state: OrderState = OrderState.RESTRICTED ) {}
@Serializable class Order(override val id: Long, val productType: ProductType, val deliveryTime: Int, val incomeTime: Int = 0 ) : AbstractAsset() { override var name: String = "$productType-order-$id" private var operations = getOperations(productType) // fixme - getters not included in serialization private var orderDetails: OrderDetails = OrderDetails( id = id, type = productType, name = name, operations = operations, plannedDeliveryTime = deliveryTime, incomeTime = incomeTime )
override val clientConfiguration: ClientConfiguration get() = TODO("Not yet implemented")
fun getState(): OrderState { return orderDetails.state }
val details: OrderDetails get() = orderDetails
fun release(time: Int) { if (orderDetails.state != OrderState.RESTRICTED) return
orderDetails.state = OrderState.PROCESSING orderDetails.releaseTime = time }
fun updateOrder(time: Int) { when (orderDetails.state) { OrderState.RESTRICTED -> { updateDeliveryTimeBuffer(time) logger.info { "Order $name is not released yet." } } OrderState.PROCESSING -> { orderDetails.operations.filter { it.state == OperationState.RESTRICTED }.forEach { updateOperationState(it) } if (orderDetails.operations.all { it.state == OperationState.DONE }) { orderDetails.state = OrderState.DONE orderDetails.actualDeliveryTime = time orderDetails.timeBuffer = orderDetails.plannedDeliveryTime.minus(time) logger.info { "Order $name is finished." } } else { updateDeliveryTimeBuffer(time) logger.info { "Order $name is in process." } } } OrderState.DONE -> logger.info { "Order $name is finished." } } } } [/code] [code]@Serializable data class OperationDetails( val id: Long, val duration: Int, val name: String, val previous: List, var cumulativeProcessTime: Int = 0, var orderDetailsType: ProductType, var orderDetailsName: String = "", @EncodeDefault var assignee: Long? = null, @EncodeDefault var startTime: Int? = null, @EncodeDefault var timeBuffer: Int = 0, @EncodeDefault var setupTime: Int = 0, @EncodeDefault var remainingProcessTime: Int = duration, @EncodeDefault var remainingSetupTime: Int = setupTime, @EncodeDefault var plannedEndTime: Int = 0, @EncodeDefault var actualEndTime: Int = 0, @EncodeDefault var state: OperationState = OperationState.RESTRICTED, @EncodeDefault var relTimeBuffer: Float = 0F, @EncodeDefault val setupTimeMatrix: MutableMap > = OrderSetupMatrix.setupTimeMatrix ) {}
@Serializable class Operation(override val id: Long, override val name: String, val assetDetails: OperationDetails ) : AbstractAsset(){ override val clientConfiguration: ClientConfiguration get() = TODO("Not yet implemented")
override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false
other as Operation
if (id != other.id) return false if (name != other.name) return false if (assetDetails != other.assetDetails) return false
return true }
override fun hashCode(): Int { var result = id.hashCode() result = 31 * result + name.hashCode() result = 31 * result + assetDetails.hashCode() return result } } [/code] [code]@Serializable data class BreakdownEvent( val workstationId: Long, val startTime: Int, var endTime: Int? )
@Serializable data class JobArrivalEvent( val arrivalTime: Int, val deliveryTime: Int, val productType: ProductType, ) [/code] Я уже пытался реализовать метод deepCopy, используя сериализацию Kotlinx для кодирования в json и последующего декодирования: [code]object SerializationUtil { inline fun deepCopy(obj: T): T { val json = Json val jsonString = json.encodeToString(serializer(), obj) return json.decodeFromString(serializer(), jsonString) } } [/code] Я написал тестовый метод для сравнения двух объектов Env. Если я инициализирую экземпляр Env и использую метод deepCopy для копирования этого экземпляра, все свойства исходного и скопированного объектов будут аналогичны. Однако при использовании метода Env.step() с одинаковыми аргументами (который изменяет такие метрики, как состояние и временной буфер операций) в обоих экземплярах Env соответственно, свойства некоторых экземпляров Operation различаются. Как правильно скопировать объект Env? Что мне не хватает?
Просто чтобы объяснить это подробнее .
У меня есть PDF-файл со следующей внутренней структурой: (см. изображение)
Catalog
Page
Kids
0000
Resources
XObject
Form1 7
Resources
XObject
Image1 3
Image2 5
Image3 7