preface: I have a part of my code that is repeated more than once and I want to create a generic method or follow a design pattern to make the code cleaner.
What I'm trying to achieve is:
- I have a JSON array each array represents a different type of employee.
- I want to sort them by
joiningDate
then convert each List to JSON again then send them to the server.
this following class represents data record for an employee.
records
denotes the data and it's in JSON format.
I parse the records data depending on the employeeType
data class EmployeeRecord(
val recordId: Long?,
val employeeType: EmployeeType,
val records: String)
This is the employee type class
@JsonClass(generateAdapter = false)
enum class EmployeeType(val role: String) {
CEO("CEO"),
CTO("CTO"),
Accountant("Accountant"),
Developer("Developer");
companion object {
val tierOneTypes: List<EmployeeType>
get() = listOf(
Developer,
Accountant
)
val tierTwoTypes: List<EmployeeType>
get() = listOf(
CEO,
CTO
)
}
}
this is the employee types
sealed class EmployeeDataRecord(open val employeeType: EmployeeType)
@JsonClass(generateAdapter = true)
internal data class CeoData(
@Json(name = "JoiningDate") val joiningDate: Long,
@Json(name = "NumberOfBranches") val numberOfBranches: Int,
@Json(name = "Address") val address: String,
@Json(name = "Salary") val salary: Long
) : EmployeeDataRecord(EmployeeType.CEO) {
companion object {
fun create(
joiningDate: Long,
numberOfBranches: Int,
address: String,
salary: Long
): CeoData {
return CeoData(
joiningDate = joiningDate,
numberOfBranches = numberOfBranches,
address = address,
salary = salary
)
}
}
}
@JsonClass(generateAdapter = true)
internal data class CtoData(
@Json(name = "HiringDate") val joiningDate: Long,
@Json(name = "NumberOfTeams") val numberOfTeams: Int,
@Json(name = "Address") val address: String,
@Json(name = "Salary") val salary: Long
) : EmployeeDataRecord(EmployeeType.CTO) {
companion object {
fun create(
joiningDate: Long,
numberOfTeams: Int,
address: String,
salary: Long
): CtoData {
return CtoData(
joiningDate = joiningDate,
numberOfTeams = numberOfTeams,
address = address,
salary = salary
)
}
}
}
@JsonClass(generateAdapter = true)
internal data class AccountantData(
@Json(name = "JoiningDate") val joiningDate: Long,
@Json(name = "Address") val address: String,
@Json(name = "Salary") val salary: Long
) : EmployeeDataRecord(EmployeeType.Accountant) {
companion object {
fun create(
joiningDate: Long,
address: String,
salary: Long
): AccountantData {
return AccountantData(
joiningDate = joiningDate,
address = address,
salary = salary
)
}
}
}
@JsonClass(generateAdapter = true)
internal data class DeveloperData(
@Json(name = "JoiningDate") val joiningDate: Long,
@Json(name = "TeamName") val teamName: String,
@Json(name = "Address") val address: String,
@Json(name = "Salary") val salary: Long
) : EmployeeDataRecord(EmployeeType.Developer) {
companion object {
fun create(
joiningDate: Long,
teamName: String,
address: String,
salary: Long
): DeveloperData {
return DeveloperData(
joiningDate = joiningDate,
teamName = teamName,
address = address,
salary = salary
)
}
}
}
here is the function that has the repeated code; as you can see createTierOneData
and createTierTwoData
have the same logic and it's repeated
class DataTest {
private fun <T> listAdapter(modelClass: Class<T>): JsonAdapter<List<T>> {
val type = Types.newParameterizedType(List::class.java, modelClass)
return moshi.adapter(type)
}
private fun createTierOneData(employeeRecords: List<EmployeeRecord>):
Pair<List<ServerAData>, List<ServerBData>> {
val serverADataList = mutableListOf<ServerAData>()
val serverBDataList = mutableListOf<ServerBData>()
val accountantDataList = mutableListOf<AccountantData>()
val developerDataList = mutableListOf<DeveloperData>()
employeeRecords.forEach {
if (it.employeeType in EmployeeType.tierOneTypes) {
when (it.employeeType) {
EmployeeType.Accountant -> listAdapter(AccountantData::class.java).fromJson(
it.records
)?.let { records -> accountantDataList.addAll(records) }
EmployeeType.Developer -> listAdapter(DeveloperData::class.java).fromJson(
it.records
)?.let { records -> developerDataList.addAll(records) }
}
}
}
if (accountantDataList.isNotEmpty()) {
if (accountantDataList.size > 1) {
accountantDataList.sortBy { it.joiningDate }
}
val serverAData = ServerAData(
EmployeeType.Accountant,
listAdapter(AccountantData::class.java).toJson(accountantDataList)
)
val serverBData = ServerBData(
EmployeeType.Developer, developerDataList.size,
159025890000
)
serverADataList.add(serverAData)
serverBDataList.add(serverBData)
}
if (developerDataList.isNotEmpty()) {
if (developerDataList.size > 1) {
developerDataList.sortBy { it.joiningDate }
}
val serverAData = ServerAData(
EmployeeType.Developer,
listAdapter(DeveloperData::class.java).toJson(developerDataList)
)
val serverBData = ServerBData(
EmployeeType.Developer, developerDataList.size,
159025890000
)
serverADataList.add(serverAData)
serverBDataList.add(serverBData)
}
return Pair(serverADataList, serverBDataList)
}
private fun createTierTwoData(employeeRecords: List<EmployeeRecord>):
Pair<List<ServerAData>, List<ServerBData>> {
val serverADataList = mutableListOf<ServerAData>()
val serverBDataList = mutableListOf<ServerBData>()
val ctoDataList = mutableListOf<CtoData>()
val ceoDataList = mutableListOf<CeoData>()
employeeRecords.forEach {
if (it.employeeType in EmployeeType.tierTwoTypes) {
when (it.employeeType) {
EmployeeType.CTO -> listAdapter(CtoData::class.java).fromJson(
it.records
)?.let { records -> ctoDataList.addAll(records) }
EmployeeType.CEO -> listAdapter(CeoData::class.java).fromJson(
it.records
)?.let { records -> ceoDataList.addAll(records) }
}
}
}
if (ctoDataList.isNotEmpty()) {
if (ctoDataList.size > 1) {
ctoDataList.sortBy { it.joiningDate }
}
val serverAData = ServerAData(
EmployeeType.CTO,
listAdapter(CtoData::class.java).toJson(ctoDataList)
)
val serverBData = ServerBData(
EmployeeType.CTO, ctoDataList.size,
159025890000
)
serverADataList.add(serverAData)
serverBDataList.add(serverBData)
}
if (ceoDataList.isNotEmpty()) {
if (ceoDataList.size > 1) {
ceoDataList.sortBy { it.joiningDate }
}
val serverAData = ServerAData(
EmployeeType.CEO,
listAdapter(CeoData::class.java).toJson(ceoDataList)
)
val serverBData = ServerBData(
EmployeeType.CEO, ceoDataList.size,
159025890000
)
serverADataList.add(serverAData)
serverBDataList.add(serverBData)
}
return Pair(serverADataList, serverBDataList)
}
}
and finally here are the ServersData classes
data class ServerAData(
val type: EmployeeType,
val dataRecord: String
)
data class ServerBData(
val type: EmployeeType,
val numberOfDataRecord: Int,
val hiringDate: Long
)
so I am trying to find a way to refactor createTierOneData
and createTierTwoData
to apply DRY. I tried to make a generic function and I failed to do it properly.
is there an approach to make these methods generic?
or if you can guide me to a design pattern that I can apply here that would be great.