Сложный объект DeepCopy с циклическими ссылками и пользовательскими геттерами с использованием сериализацииAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Сложный объект DeepCopy с циклическими ссылками и пользовательскими геттерами с использованием сериализации

Сообщение Anonymous »

Я написал сложный класс Kotlin Env, в котором мне нужно реализовать метод deepCopy. Вот минимальный репродуктивный пример класса и классов, на которые он ссылается:

Код: Выделить всё

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

timeBufferList.addAll(job.getTimeBufferList())
}

jobPool.forEach { job ->
job.updateShopCapacity(
workstationPool.count { it.state != WorkstationState.FAILURE },
jobPool.count { it.getState() == OrderState.PROCESSING }
)

job.details.operations.filter { it.assignee == null }.forEach { operationDetails ->
val relTimeBuffer = if (timeBufferList.max() != 0) operationDetails.timeBuffer.div(timeBufferList.max().toFloat()) else 1F
operationDetails.relTimeBuffer = relTimeBuffer
}
}

time += 1

val terminated = jobPool.all { it.getState() == OrderState.DONE }
return Triple(terminated, workstationPool, jobPool)
}

fun deepCopy(): DiscreteSchedulingEnv {
return deepCopy(this)
}

}

Код: Выделить всё

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

}

Код: Выделить всё

@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? Что мне не хватает?

Подробнее здесь: https://stackoverflow.com/questions/785 ... g-serializ
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»