Home > Mobile >  Is it proper to use an enumeration in this way?
Is it proper to use an enumeration in this way?

Time:10-18

I'm making an android game in Kotlin and I'm wondering about the use of my enumeration. It looks like this:

package com.example.makemoremeat.enumerations

import com.example.makemoremeat.R

enum class ProductionInformation(
    val initialNumber: Double,
    val initialCost: Double,
    val initialProduction: Double,
    val initialProductionTime: Double,
    val coefficientCostUp: Double,
    val imageProduction: Int
) {

    Chicken(1.0, 1.0, 0.1, 1.0, 1.13, R.drawable.production_work_in_progress),
    Beef(0.0, 7.0, 0.7, 2.0, 1.14, R.drawable.production_work_in_progress),
    Mutton(0.0, 49.0, 4.9, 4.0, 1.15, R.drawable.production_work_in_progress),
    Pork(0.0, 343.0, 34.3, 8.0, 1.16, R.drawable.production_work_in_progress),
    Rabbit(0.0, 2401.0, 240.1, 16.0, 1.17, R.drawable.production_work_in_progress),
    Horse(0.0, 16807.0, 1680.7, 32.0, 1.18, R.drawable.production_work_in_progress),
    Caribou(0.0, 117650.0, 11765.0, 64.0, 1.19, R.drawable.production_work_in_progress),
    Fish(0.0, 823540.0, 82354.0, 128.0, 1.20, R.drawable.production_work_in_progress),
    Dog(0.0, 5764800.0, 576480.0, 256.0, 1.21, R.drawable.production_work_in_progress),
    Elephant(0.0, 40354000.0, 4035400.0, 512.0, 1.22, R.drawable.production_work_in_progress),
    Bugs(0.0, 282480000.0, 28248000.0, 1024.0, 1.23, R.drawable.production_work_in_progress),
    Vegan(0.0, 1977300000.0, 197730000.0, 2048.01, 1.24, R.drawable.production_work_in_progress),
    Cultured(0.0, 13841000000.0, 1384100000.0, 4096.0, 1.25, R.drawable.production_work_in_progress)
}

And I use it this way:

class Production (
    private val game: Game,
    private val productionInformation: ProductionInformation
) {

    val image = productionInformation.imageProduction
    var numberPossessed = productionInformation.initialNumber
    var actualCost =
        productionInformation.initialCost * productionInformation.coefficientCostUp.pow(
            numberPossessed - 1
        )
    var actualProduction = productionInformation.initialProduction
    var actualProductionTime = productionInformation.initialProductionTime
[...]

Is it clean? Or else what would be the way to do in this case? Inheritance with 13 classes extending Production would be better? Thanks for your help !

CodePudding user response:

Inheritance with multiple classes would definitely be worse! There is nothing here that necessitates different classes. None of these items need a unique property or function type.

It is an OK pattern in some cases. But if you don't really need to enforce a specific, finite set of possible items, a regular class, maybe data class, would be sufficient. For example, if you don't need to use when statements on it to treat each possible member differently, or be able to iterate all possible values, then making it an Enum class doesn't really buy you anything, and it limits where you can define instances. Your code above suggests no reason why this shouldn't just be a data class.

Since you have many entries, possibly it should be loaded from a resource like a JSON file pre-prepared database file.

CodePudding user response:

enums or "enumerated/enumaration data type", are widely used for selection constructs, use-cases where your logic would follow a certain path based on the enum you provide, consider the following, each described by a simple requirement

Case 1:

Cold or Hot food, if the customer ordered a cold food, serve the customer with a jacket, if the customer orders a hot food, give him a bucket of ice

enum class FoodOrderType {
    COLD, HOT
}

somewhere in my code

val foodType = customer.getOrderedFoodType()

when (foodType) {
     FoodOrderType.COLD -> {
          // free jacket
      }
      FoodOrderType.HOT -> {
          // a bucket of ice
      }
}

Case 2:

Depending on specific volume level of your car's current gasoline, make a decision whether to continue driving? get your wallet ready?, or look for a nearest gas station

enum class GasolineLevel {
    FULL, HALF, QUARTER
}

somewhere in my code

 val gasolineLevel = car.getGasolineLevel()

when (gasLevel) {
    GasolineLevel.FULL -> {
        // continue driving
    }
    GasolineLevel.HALF -> {
        // get your wallet ready
    }
    GasolineLevel.QUARTER -> {
        // look for the nearest station
    }
}

You can see that most of the examples above revolves around how your code flow will decide continuing, however in your question, it doesn't seem to warrant something for a "decisional" or "conditional" flow of code, its just an enum representing a series of characteristics Inherited by certain constructs.

Personally I see your code falling into an Inheritance Design, where your

  • Chicken
  • Beef
  • Mutton
  • Pork
  • etc...

inherits their characteristics from ProductionInformation like

class Chicken : ProductInformation{ 
      ...
}

or

class Beef: ProductInformation{ 
      ...
}

or better yet, keeping the context intact you should suffix your class names based on its context like the following

class ChickenProduct : ProductInformation { 
      ...
}

or

class BeefProduct : ProductInformation{ 
      ...
}

There is nothing wrong with your code, but there are certain OOP principles that makes sense for certain use-cases.

Edit: I agree with Tenfour04, composition is the most ideal design strategy for your use-case, instead of a bloated package/directory full of similar classes with different names, Prefer composition over inheritance

  • Related