Scala Book

An OOP Example

Language

This lesson shares an example of an OOP application written with Scala. The example shows code you might write for an order-entry system for a pizza store.

As shown earlier in the book, you create enumerations in Scala like this:

sealed trait Topping
case object Cheese extends Topping
case object Pepperoni extends Topping
case object Sausage extends Topping
case object Mushrooms extends Topping
case object Onions extends Topping

sealed trait CrustSize
case object SmallCrustSize extends CrustSize
case object MediumCrustSize extends CrustSize
case object LargeCrustSize extends CrustSize

sealed trait CrustType
case object RegularCrustType extends CrustType
case object ThinCrustType extends CrustType
case object ThickCrustType extends CrustType

A nice thing about Scala is that even though we haven’t discussed sealed traits or case objects, you can probably still figure out how this code works.

A few classes

Given those enumerations, you can now start to create a few pizza-related classes for an order-entry system. First, here’s a Pizza class:

import scala.collection.mutable.ArrayBuffer

class Pizza (
    var crustSize: CrustSize,
    var crustType: CrustType,
    var toppings: ArrayBuffer[Topping]
)

Next, here’s an Order class, where an Order consists of a mutable list of pizzas and a Customer:

class Order (
    var pizzas: ArrayBuffer[Pizza],
    var customer: Customer
)

Here’s a Customer class to work with that code:

class Customer (
    var name: String,
    var phone: String,
    var address: Address
)

Finally, here’s an Address class:

class Address (
    var street1: String,
    var street2: String,
    var city: String,
    var state: String,
    var zipCode: String
)

So far those classes just look like data structures — like a struct in C — so let’s add a little behavior.

Adding behavior to Pizza

For the most part an OOP Pizza class needs a few methods to add and remove toppings, and adjust the crust size and type. Here’s a Pizza class with a few added methods to handle those behaviors:

class Pizza (
    var crustSize: CrustSize,
    var crustType: CrustType,
    val toppings: ArrayBuffer[Topping]
) {

    def addTopping(t: Topping): Unit = toppings += t
    def removeTopping(t: Topping): Unit = toppings -= t
    def removeAllToppings(): Unit = toppings.clear()

}

You can also argue that a pizza should be able to calculate its own price, so here’s another method you could add to that class:

def getPrice(
    toppingsPrices: Map[Topping, Int],
    crustSizePrices: Map[CrustSize, Int],
    crustTypePrices: Map[CrustType, Int]
): Int = ???

Note that this is a perfectly legal method. The ??? syntax is often used as a teaching tool, and sometimes you use it as a method-sketching tool to say, “This is what my method signature looks like, but I don’t want to write the method body yet.” A great thing for those times is that this code compiles.

That being said, don’t call that method. If you do, you’ll get a NotImplementedError, which is very descriptive of the situation.

Adding behavior to Order

You should be able to do a few things with an order, including:

  • Add and remove pizzas
  • Update customer information
  • Get the order price

Here’s an Order class that lets you do those things:

class Order (
    val pizzas: ArrayBuffer[Pizza],
    var customer: Customer
) {

    def addPizza(p: Pizza): Unit = pizzas += p
    def removePizza(p: Pizza): Unit = pizzas -= p

    // need to implement these
    def getBasePrice(): Int = ???
    def getTaxes(): Int = ???
    def getTotalPrice(): Int = ???

}

Once again, for the purposes of this example, we’re not concerned with how to calculate the price of an order.

Testing those classes

You can use a little “driver” class to test those classes. With the addition of a printOrder method on the Order class and a toString method in the Pizza class, you’ll find that the code shown works as advertised:

import scala.collection.mutable.ArrayBuffer

object MainDriver extends App {

    val p1 = new Pizza (
        MediumCrustSize,
        ThinCrustType,
        ArrayBuffer(Cheese)
    )

    val p2 = new Pizza (
        LargeCrustSize,
        ThinCrustType,
        ArrayBuffer(Cheese, Pepperoni, Sausage)
    )

    val address = new Address (
        "123 Main Street",
        "Apt. 1",
        "Talkeetna",
        "Alaska",
        "99676"
    )

    val customer = new Customer (
        "Alvin Alexander",
        "907-555-1212",
        address
    )

    val o = new Order(
        ArrayBuffer(p1, p2),
        customer
    )

    o.addPizza(
        new Pizza (
            SmallCrustSize,
            ThinCrustType,
            ArrayBuffer(Cheese, Mushrooms)
        )
    )

    // print the order
    o.printOrder

}

Experiment with the code yourself

To experiment with this on your own, please see the PizzaOopExample project in this book’s GitHub repository, which you can find at this URL:

To compile this project it will help to either (a) use IntelliJ IDEA or Metals, or (b) know how to use the Scala Build Tool.

Contributors to this page: