Search code examples
scalatype-variables

Placing items of different types in a list with being able to map on them


So I made a post earlier about accessing a field of a subclass from within the superclass to solve a problem i have. But they made it clear that it is practically impossible. So I made a little example of what i want to achieve:

abstract class LotteryTicket(val numbers: String) { 

val price: Int

}

//The numbers are different for each ticket and are used to denote a winner in the end.

class GoldTicket(numbers: String) extends LotteryTicket(person) {

val price: Int = 10

}

class SilverTicket(numbers: String) extends LotteryTicket(person) {

val price: Int = 5

}

abstract class Drink {

val price: Int

}

object Water extends Drink {

val price: Int = 1

}

object Coffee extends Drink {

val price: Int = 2

}

class Bill

class Customer

The class 'Bill' should contain a list which can include Drinks as well as LotteryTickets, for which the total can be calculated and the Customer has to be able to make such a bill. The Customer class also needs a method which confirms the purchase and checks if the numbers on his LottoryTicket are different for every Ticket he bought. Because when he has the same number on 2 tickets The confirmation fails. It alse must be possible to add new products in the future (like food for example) in an easy way (without changing the core code).


Solution

  • You want your "billable" items implement a trait, that exposes their common features.

      trait Billable { 
          def price: Int
      }
      class LotteryTicket(val numbers: String, val price: Int) extends Billable
      class GoldTicket(n: String) extends LotteryTicket(n, 10)
      class SilverTockent(n: String) extends LotteryTicket(n, 5)
    
      class Drink(val price: Int) extends Billable
      object Water extends Drink(1)
      object Coffee extends Drink(2)
    
      case class Bill(val items: Seq[Billable]= Seq.empty)
      {
        def amount = items.map(_.price).sum
        def add(b: Billable) = copy(b +: items)
      }
    
      case class Customer(bill: Bill = Bill()) {
        def buy(ticket: LotteryTicket) = {
          // validate numbers, whatever
          Customer(bill.add(ticket))
        }
    
        def buy(drink: Drink) = {
          Customer(bill.add(drink)
        }
    
        def howMuch = bill.total
    
        def validateAllTickets = bill.items.foreach {
           case ticket: LotteryTicket => makeSureNumberIsGood(ticket.numbers)
           case _ =>
        }
      }