Description
Topics:
- Basics of Objects
- Type Constraints.
Name: WRITE YOUR NAME HERE
// TEST HELPER
def passed(points: Int) {
require(points >=0)
if (points == 1) print(s"\n*** Tests Passed (1 point) ***\n")
else print(s"\n*** Tests Passed ($points points) ***\n")
}
Problem 1 (20 points): Objects in Scala
A (12 points)
Consider the class below for an employee record in an organization that has three fields name
, eid
(employee id) and salary
.
1) As given, scala will complain that class employee cannot extend the abstract class People. Add the missing methods to enable the class Employee to properly extend People
2) Write a factory pattern that takes in a formatted string of the form “John Doe,29585,33110” consisting of a string and two numbers, to extract the name and salaries for each employee. You may want to use scala.util.matching.Regex
[https://www.scala-lang.org/api/2.9.2/scala/util/matching/Regex.html] If the input fails to match the pattern, an IllegalArgumentException
must be thrown
Companion objects are covered in scala book Chapter 4.3. Also lookup here: https://alvinalexander.com/scala/factory-pattern-in-scala-design-patterns
import scala.util.matching.Regex
abstract class People {
/* I need the ability to convert every person to a string */
def toString: String
/* I need the ability to check if two people are the same */
def equals (p: People): Boolean
}
/*
Note that for an employee to be equal to an object of type People, that object
must be an employee with matching eid number
*/
class Employee( val name: String, val eid: Int, var salary: Int) extends People {
??? // YOUR CODE HERE
}
object Employee {
def apply(formattedInput: String): Employee = {
/*
Input format must be
(full name with possible spaces)[optional whitespaces],[optional whitespaces](employee ID number)[optional whitespaces],[optional whitespaces](employee salary)
*/
??? // YOUR CODE HERE
}
}
//BEGIN TEST
val e1 = Employee("Jonathan Doe, 12893, 39813")
println(e1.toString)
assert(e1.name == "Jonathan Doe", "Failed")
assert(e1.eid == 12893, "Failed")
assert(e1.salary == 39813, "Failed")
assert(e1.equals(new Employee("whoknows", 12893, 39813)))
passed(4)
//END TEST
//BEGIN TEST
try {
val e2 = Employee("Badly Formatted String, 29812, $3102")
assert(false, "Failed, the string is badly formatted but your code is OK with it.")
} catch {
case e => println(s"Expected behavior seen")
}
passed(4)
//END TEST
//BEGIN TEST
val e1 = Employee("Janet Maria Catherine Doe , 12894 , 121331")
println(e1.toString)
assert(e1.name == "Janet Maria Catherine Doe", "Failed")
assert(e1.eid == 12894, "Failed")
assert(e1.salary == 121331, "Failed")
assert(e1.equals(new Employee("random", 12894, 121332)))
passed(4)
//END TEST
B (8 points)
We wish to add a new class of people to our system. These are “Contractor” with the information associated should involve their name (string), contract ID (Integer) and contract supervisor (Employee).
Write a new class named Contractor
whose constructor should take in the name of the person (String), their ID number (Integer) and Supervisor (Employee) and extend from People.
A contractor object is equal to an object p of type People, only if p is actually an instance of contractor, and if their names are the same and they have the same contract ID number.
??? // YOUR CODE HERE
//BEGIN TEST
val e1 = Employee("Jonathan Doe, 12893, 39813")
val c1 = new Contractor("John Contract Worker", 12093, e1)
assert( !c1.equals(e1), "Failed")
assert( c1.equals(c1), "Failed")
passed(4)
//END TEST
//BEGIN TEST
val e1 = Employee("Jonathan Doe, 12893, 39813")
val e2 = Employee("Jane Doe, 12894, 43814")
val c1 = new Contractor("John Contract Worker", 12093, e2)
val c2 = new Contractor("John Contract Worker", 12093, e1)
assert( c1.equals(c2), "Failed")
passed(4)
//END TEST
Problem 2 (25 points): Traits in Scala
For this problem, we have defined two traits: NumberOfLegs
that helps us define how many legs a given animal has and WarmBlooded
that applies to warm blooded animals.
abstract class Animal
trait NumberOfLegs {
val nLegs: Int
def getNumberOfLegs: Int = nLegs
}
trait WarmBlooded extends Animal {
val bodyTempMaintained: Double
def getBodyTemp: Double = bodyTempMaintained
}
A (5 points)
Define a class Human
that inherits from Animal
and mixes in the traits NumberOfLegs
with nLegs = 2
and WarmBlooded
with bodyTempMaintained = 98
. The class Human
must take in a parameter called name
of type String
and implement a getName
method without any parameters.
??? // YOUR CODE HERE
//BEGIN TEST
val t1 = new Human("Jane Smith")
assert(t1.getNumberOfLegs == 2, "Your human does not have two legs")
assert(t1.bodyTempMaintained == 98.0, "Your human does not maintain a body temp of 98")
assert(t1.getBodyTemp == 98.0, "Your human's getBodyTemp Function is not working")
assert(t1.getName == "Jane Smith", "Your human's name is not setting correctly")
passed(5)
//END TEST
B (5 points)
Define a class named Table
that mixes in the trait NumberOfLegs
with nLegs = 4
.
Note: Table
cannot mixin the trait WarmBlooded
(make sure you understand why that is as a quick check of concepts).
??? // YOUR CODE HERE
//BEGIN TEST
val tbl = new Table()
assert(tbl.getNumberOfLegs == 4, "A Table must have four legs")
passed(5)
//END TEST
C (15 points)
Define a class called Menagerie
with type parameter T
such that
- T must always be a derived type of Animal with the trait NumberOfLegs (In scala you can say
T <: A with B
to indicate that a type parameter T must derive from class A with trait B applied). Menagerie
has a list of objects of typeT
.- The user must be able to instantiate an object of type Menagerie without providing any class parameters:
new Menagerie[T]
- The class Menagerie has the method
addAnimalToMenagerie
that adds an object of typeT
to menagerie and returns a new Menagerie. - Implement a method
addMultipleAnimalsToMenagerie
that adds more than one animal. - Add a method
totalLegs: Int
that sums up how many legs the animals in the menagerie have in total.
Here is the template for your solution below.
class Menagerie[T ..constraints..] ( ..class params..) {
// ... Extra Stuff that you may want to add ...
def addAnimalToMenagerie (a: T) : Menagerie[T] = {
// Implement
}
def addMultipleAnimals(animals: List[T]): Menagerie[T] = {
// Implement
}
def totalLegs:Int = {
// Implement
}
}
??? // YOUR CODE HERE
//BEGIN TEST SETUP
class Donkey extends Animal with NumberOfLegs with WarmBlooded {
val nLegs:Int = 4
val bodyTempMaintained = 96.0
}
class Lion extends Animal with NumberOfLegs {
val nLegs:Int = 4
}
class Mule extends Donkey
val d1 = new Donkey()
val d2 = new Donkey()
val d3 = new Donkey()
val d4 = new Mule()
//END TEST SETUP
//BEGIN TEST
val m1 = new Menagerie[Donkey](Nil)
passed(3)
//END TEST
//BEGIN TEST
val m1 = new Menagerie[Donkey](Nil)
val m2 = m1.addAnimalToMenagerie(d1)
val n = m2.totalLegs
assert(n == 4, s"1 quadraped = 4 legs. You have $n legs : are you missing legs? Too many legs?")
passed(6)
//END TEST
//BEGIN TEST
val m1 = new Menagerie[Donkey](Nil)
val m2 = m1.addMultipleAnimalsToMenagerie(List(d1, d2, d3, d4))
val n = m2.totalLegs
assert(n == 16, s"4 quadrapeds = 16 legs. You have $n legs : are you missing legs? Too many legs?")
passed(6)
//END TEST