Topic I –Enumerations and Composition
Overview
This topic introduces enumerations and composition. The following new keywords are introduced.
- enum
This topic will reveal how enumerations allow programmers to define new data types and values to represent conceptual information. This topic also discusses the concept of composition, describing how composition is simply the use of objects as fields in a class.
### LOGs
General Programming Concepts and Terms
- Define the term Enumeration
- List the benefits of using enumerations
- Describe where and when enumerations are used
- Compare and contrast enumerations and classes
- Use enumerations to define simple data types that are conceptual in nature and that have a limited set of possible “values”
OOP Basics
- Describe the idea of Composition
- List the benefits of Composition
Code Samples
Enumerations:
- Coin + CoinFace – The CoinFace enumeration helps to describe the tw * sides of a Coin, which can then be used in a tossing game.
- Account + AccountType – The Account’s account type is n * longer being represented as a string, but is its own enumeration: AccountType.
- LetterGrade + QuebecLetterGrade – The QuebecLetterGrade uses the simple LetterGrade enumeration and assigns specific ranges of percentage marks for the possible LetterGrade values.
Composition:
- Address + Student + GenderType – This revised version of the Student class now has an Address field. The address field is new; although similar to the CanadianAddress class, the Address class is simpler and more “generic” (having “State” instead of “Province” and “ZipCode” instead of “PostalCode”).
- ImproperFraction + MixedNumber + ProperFraction – In this sample, the idea of a Fraction class is made more specific by replacing it with three more specific types of numbers: MixedNumber, ProperFraction, and ImproperFraction. A MixedNumber is made up of a whole number and a ProperFraction. A MixedNumber can also be expressed as or derived from an ImproperFraction. The reciprocal of a ProperFraction is an ImproperFraction and the reciprocal of an ImproperFraction is a ProperFraction.
Coin + CoinFace
The CoinFace enumeration helps to describe the tw * sides of a Coin, which can then be used in a tossing game.
Problem Statement
Write the code needed to represent a coin that could be used in a coin-toss game. The solution must meet the following requirements.
- Should randomly generate the coin face that is showing when creating the coin
- Should get the side of the coin that is face showing
- Should allow the coin to be tossed to randomly generate a new coin face
- Should only support tw * sides for a coin’s face: Heads and Tails
Use the following diagram when creating your solution.
1 public class Coin
2 {
3 public enum CoinFace { HEADS, TAILS };
4
5 public CoinFace FaceShowing { get; private set; }
6
7 public Coin()
8 {
9 Toss();
10 }
11
12 public void Toss()
13 {
14 if (Rnd.Next(2) == 0)
15 FaceShowing = CoinFace.HEADS;
16 else
17 FaceShowing = CoinFace.TAILS;
18 }
19 }
Account + AccountType
The Account’s account type is n * longer being represented as a string, but is its own enumeration: AccountType.
Problem Statement
Write the code that will make the account type a type-safe value for the Account class. The solution must meet the following requirements (new requirements are in bold):
- Should get the bank name, branch number, institution number, account number, balance, overdraft limit, and account type and allow the overdraft limit to be set
- Should support deposits
- Should only support withdrawals if the amount does not exceed the sum of the balance and the overdraft limit, otherwise an exception stating “Insufficient Funds” should occur
- Should identify if the account is overdrawn
- Should require bank name and account type (that is, they cannot be empty or null)
- Should trim the bank name
- Should ensure that the Account Type is type-safe and that it is supplied when creating the account (that is, it cannot be null)
- Should support the following types of accounts: Chequing, Saving, Credit Card, and Line of Credit
- Should verify that the branch number is six digits and the institution number is three digits
- Should require an opening balance
- Should not allow a negative overdraft limit
Use the following class diagram when creating your solution.
1 public class Account
2 {
3 public Account(string bankName, int branchNumber, int institutionNumber,
4 int accountNumber, double balance, double overdraftLimit,
5 AccountType type)
6 {
7 if (string.IsNullOrEmpty(bankName) ||
8 string.IsNullOrEmpty(bankName.Trim()))
9 throw new System.Exception("Bank name cannot be empty");
10 if (branchNumber < 10000 || branchNumber > 99999)
11 throw new System.Exception("Branch number must be 5 digits");
12 if (institutionNumber < 100 || institutionNumber > 999)
13 throw new System.Exception("Institution number must be 3 digits");
14 if (balance <= 0)
15 throw new System.Exception("Opening balance must be greater than zer\
16 o");
17 OverdraftLimit =overdraftLimit;
18 this.BankName = bankName;
19 this.BranchNumber = branchNumber;
20 this.InstitutionNumber = institutionNumber;
21 this.AccountNumber = accountNumber;
22 this.Balance = balance;
23 this.Type = type;
24 }
25
26 private double _overdraftLimit;
27
28 public double Balance { get; private set; }
29 public string BankName { get; private set; }
30 public int BranchNumber { get; private set; }
31 public int InstitutionNumber { get; private set; }
32 public int AccountNumber { get; private set; }
33 public AccountType Type { get; private set; }
34
35 public double OverdraftLimit
36 {
37 get
38 { return _overdraftLimit; }
39 set
40 {
41 if (value < 0)
42 throw new System.Exception("Negative overdraft limits not allowe\
43 d");
44 this._overdraftLimit = value;
45 }
46 }
47
48 public bool IsOverdrawn()
49 {
50 return Balance < 0.0;
51 }
52
53 public void Deposit(double amount)
54 {
55 Balance += amount;
56 }
57
58 public double Withdraw(double amount)
59 {
60 if (amount > Balance + _overdraftLimit)
61 throw new System.Exception("Insufficient Funds");
62 Balance -= amount;
63 return amount;
64 }
65 }
LetterGrade + QuebecLetterGrade
The QuebecLetterGrade uses the simple LetterGrade enumeration and assigns specific ranges of percentage marks for the possible LetterGrade values.
Problem Statement
Write the code for the LetterGrade class that represents a letter grade as assigned in Quebec universities (Source: http://en.wikipedia.org/wiki/Letter_grade). The solution must meet the following requirements (new requirements are in bold):
- Should get and set the grade as a type-safe value
- Should get the appropriate descriptions for the grade, based on the following table:
| Grade | Description |
| A | A - 80-100% - Greatly Above Standards |
| B | B - 70-79% - Above Standards |
| C | C - 60-69% - At Government Standards |
| D | D - 50-60% - Lower Standards |
| F | F - 0-49% - Failure |
Use the following class diagram when creating your solution.
1 public enum LetterGrade
2 {
3 A, B, C, D, F
4 }
5
6 public class QuebecLetterGrade
7 {
8 public LetterGrade Grade { get; set; }
9
10 public QuebecLetterGrade(LetterGrade grade)
11 {
12 this.Grade = grade;
13 }
14
15 public override string ToString()
16 {
17 string description;
18 switch (Grade)
19 {
20 case LetterGrade.A:
21 description = "A - 80-100% - Greatly Above Standards";
22 break;
23 case LetterGrade.B:
24 description = "B - 70-79% - Above Standards";
25 break;
26 case LetterGrade.C:
27 description = "C - 60-69% - At Government Standards";
28 break;
29 case LetterGrade.D:
30 description = "D - 50-60% - Lower Standards";
31 break;
32 case LetterGrade.F:
33 description = "F - 0-49% - Failure";
34 break;
35 default:
36 description = "Invalid Letter Grade";
37 break;
38 }
39 return description;
40 }
41 }
Address + Student + GenderType
This revised version of the Student class now has an Address field. The address field is new; although similar to the CanadianAddress class, the Address class is simpler and more “generic” (having “State” instead of “Province” and “ZipCode” instead of “PostalCode”).
Problem Statement
Extend the Student class to now include information about the student’s home address. Create an Address class to represent a simple, generic address. In addition, the Student class must represent the Gender using an enumeration.
The solution must meet the following requirements (new requirements are in bold):
-
The Address class must
- Get and set the city, state, street, unit and zip code.
- The Student class must
- Verify that an address object is supplied (is not null)
- Represent the Gender as a GenderType of Male and Female
- Should get and set the student’s name, gender, GPA, program of studies, and whether or not the student is full-time.
- Should override the toString() method to get the student’s ID and name in this format:
(ID) Name - Should n * longer allow the student ID to be set (it’s only set through the constructor)
- Should reject empty text (and null values) for the student’s name and program of studies.
- Should trim the student’s name and the program name
- Should only accept ‘M’ and ‘F’ as valid genders
- Should set the gender to upper-case
- Should reject negative GPAs and GPAs over 9
Use the following class diagrams to guide your design.
1 public enum GenderType
2 {
3 MALE, FEMALE
4 }
5
6 public class Address
7 {
8 public string Street { get; set; }
9 public string Unit { get; set; }
10 public string City { get; set; }
11 public string State { get; set; }
12 public string ZipCode { get; set; }
13
14 public Address(string unit, string street, string city, string state,
15 string zipCode)
16 {
17 this.Unit = unit;
18 this.Street = street;
19 this.City = city;
20 this.State = state;
21 this.ZipCode = zipCode;
22 }
23 }
24
25 public class Student
26 {
27 private string _name; // The full name of the student
28 private string _program; // The course program; e.g.: "CST"
29 private double _gradePointAverage; // GPA is from 1.0 to 9.0
30 private Address _homeAddress;
31
32 public Student(string name, Address homeAddress, GenderType gender,
33 int studentId, string program, double gradePointAverage,
34 bool isFullTime)
35 {
36 if (studentId < 100000000 || studentId > 999999999)
37 throw new System.Exception("Student Ids must be 9 digits");
38 Name = name;
39 HomeAddress = homeAddress;
40 Gender = gender;
41 StudentId = studentId;
42 Program = program;
43 GradePointAverage = gradePointAverage;
44 IsFullTime = isFullTime;
45 }
46
47 public GenderType Gender { get; set; }
48 public bool IsFullTime { get; set; }
49 public int StudentId { get; private set; }
50
51 public string Name
52 {
53 get
54 { return _name; }
55 set
56 {
57 if (string.IsNullOrEmpty(value) ||
58 string.IsNullOrEmpty(value.Trim()))
59 throw new System.Exception("name cannot be empty");
60 this._name = value.Trim();
61 }
62 }
63
64 public Address HomeAddress
65 {
66 get
67 { return _homeAddress; }
68 set
69 {
70 if (value == null)
71 throw new System.Exception("Address is required");
72 this._homeAddress = value;
73 }
74 }
75
76 public string Program
77 {
78 get
79 { return _program; }
80 set
81 {
82 if (string.IsNullOrEmpty(value) ||
83 string.IsNullOrEmpty(value.Trim()))
84 throw new System.Exception("Program cannot be empty");
85 this._program = value.Trim();
86 }
87 }
88
89 public double GradePointAverage
90 {
91 get
92 { return _gradePointAverage; }
93 set
94 {
95 if (value < 0 || value > 9)
96 throw new System.Exception("GPA must be between 0 and 9 inclusiv\
97 e");
98 this._gradePointAverage = value;
99 }
100 }
101
102
103 public override string ToString()
104 {
105 return "(" + StudentId + ") " + Name;
106 }
107 }
ImproperFraction + MixedNumber + ProperFraction
In this sample, the idea of a Fraction class is made more specific by replacing it with three more specific types of numbers: MixedNumber, ProperFraction, and ImproperFraction. A MixedNumber is made up of a whole number and a ProperFraction. A MixedNumber can also be expressed as or derived from an ImproperFraction. The reciprocal of a ProperFraction is an ImproperFraction and the reciprocal of an ImproperFraction is a ProperFraction.
Problem Statement
The generic Fraction class is now being replaced with a set of three more specific classes for numbers with fractional values: ProperFraction, ImproperFraction, and MixedNumber. Create these classes, using the following requirements and class diagrams.
- ProperFraction should ensure that it is indeed a proper fraction
- ImproperFraction should ensure that it is indeed an improper fraction
- MixedNumber should construct either from a whole number and a proper fraction or from an improper fraction
- ProperFraction and ImproperFraction should get their respective reciprocals as well as their values as real numbers
- ProperFraction and ImproperFraction should ensure that the denominator is always positive
- MixedNumber should get the whole number portion as well as the fractional portion
- MixedNumber should get its value as a real number as well as get its value as an ImproperFraction
1 public class ProperFraction
2 {
3 public ProperFraction(int numerator, int denominator)
4 {
5 if (denominator == 0)
6 throw new System.Exception("zero denominator fractions are undefined\
7 ");
8 if (Math.Abs(numerator) >= Math.Abs(denominator))
9 throw new System.Exception("Proper fractions must have a numerator t\
10 hat is less than the denominator");
11
12 if (denominator < 0)
13 {
14 numerator *= -1;
15 denominator *= -1;
16 }
17 this.Numerator = numerator;
18 this.Denominator = denominator;
19 }
20
21 public int Numerator { get; private set; }
22 public int Denominator { get; private set; }
23 public ImproperFraction Reciprocal
24 {
25 get
26 { return new ImproperFraction(Denominator, Numerator); }
27 }
28
29 public double ToDouble()
30 {
31 return (double)(Numerator) / Denominator;
32 }
33
34 public override string ToString()
35 {
36 return Numerator + "/" + Denominator;
37 }
38 }
39
40 public class ImproperFraction
41 {
42 public ImproperFraction(int numerator, int denominator)
43 {
44 if (denominator == 0)
45 throw new System.Exception("zero denominator fractions are undefined\
46 ");
47 if (Math.Abs(numerator) < Math.Abs(denominator))
48 throw new System.Exception("Improper fractions must have a numerator\
49 that is greater than or equal to the denominator");
50
51 if (denominator < 0)
52 {
53 numerator *= -1;
54 denominator *= -1;
55 }
56 this.Numerator = numerator;
57 this.Denominator = denominator;
58 }
59
60 public int Numerator { get; private set; }
61 public int Denominator { get; private set; }
62 public ProperFraction Reciprocal
63 {
64 get { return new ProperFraction(Denominator, Numerator); }
65 }
66
67 public double ToDouble()
68 {
69 return (double)(Numerator) / Denominator;
70 }
71
72 public override string ToString()
73 {
74 return Numerator + "/" + Denominator;
75 }
76 }
77
78 public class MixedNumber
79 {
80 public int WholeNumber { get; private set; }
81 public ProperFraction Fraction { get; private set; }
82
83 public MixedNumber(int wholeNumber, ProperFraction fraction)
84 {
85 if (wholeNumber == 0)
86 throw new System.Exception("wholeNumber portion cannot be zero for a\
87 Mixed Number");
88 if (fraction == null)
89 throw new System.Exception("MixedNumbers must have a fractional port\
90 ion");
91 if (fraction.Numerator < 0)
92 {
93 fraction = new ProperFraction(-fraction.Numerator, fraction.Denomina\
94 tor);
95 wholeNumber *= -1;
96 }
97 this.WholeNumber = wholeNumber;
98 this.Fraction = fraction;
99 }
100
101 public MixedNumber(ImproperFraction improperFraction) :
102 this(improperFraction.Numerator / improperFraction.Denominator,
103 new ProperFraction(improperFraction.Numerator %
104 improperFraction.Denominator,
105 improperFraction.Denominator))
106 {
107 }
108
109 public ImproperFraction ToImproperFraction()
110 {
111 return new ImproperFraction(WholeNumber *
112 Fraction.Denominator + Fraction.Numerator,
113 Fraction.Denominator);
114 }
115
116 public double ToDouble()
117 {
118 double realValue = Math.Abs(WholeNumber) + Fraction.ToDouble();
119 if (WholeNumber < 0)
120 realValue *= -1;
121 return realValue;
122 }
123 }
Practice Exercises
- LetterGrade + BahamaLetterGrade – The BahamaLetterGrade also uses the LetterGrade enumerated type, assigning its own specific ranges and values to the possible LetterGrade values.
- HazardousMaterial + ClassCode – The various types of hazardous materials are now identified by their ClassCode enumerated type.
- CanadianAddress + Province – The CanadianAddress class is modified to now use a Province enumeration to properly capture the provinces and territories of Canada.
- Employee/Student + CanadianAddress + Province – The Employee and Student classes now have address information.
- Company + Month + CanadianAddress + Province – The Company now has a CanadianAddress.
LetterGrade + BahamaLetterGrade
The BahamaLetterGrade also uses the LetterGrade enumerated type, assigning its own specific ranges and values to the possible LetterGrade values.
Problem Statement
Write the code for the BahamaLetterGrade class and the LetterGrade enumeration to represent a letter grade as assigned in universities in the Bahamas. (For more information on Bahaman letter grades, see http://en.wikipedia.org/wiki/Letter_grade.) . The solution must meet the following requirements (new requirements are in green, bold italic font):
- The LetterGrade enumeration should be “generic” and support letter grades of A through F inclusive
- The BahamaLetterGrade should reject the LetterGrade of E (which is not allowed in the Bahamas) as well as any null letter grade
- The BahamaLetterGrade should get the appropriate descriptions for the grade, based on the following table:
| Grade | Grade | Value Description |
|---|---|---|
| A | 4 | A-4 - 90-100% |
| B | 3 | B-3 - 71-89% |
| C | 2 | C-2 - 56-70% |
| D | 1 | D-1 - 46-55% |
| F | 0 | F-0 - 0-45% |
Use the following class diagram when creating your solution.
HazardousMaterial + ClassCode
The various types of hazardous materials are now identified by their ClassCode enumerated type.
Problem Statement
Rewrite the code for the HazardousMaterial class to make use of the ClassCode enumerated type. The solution must meet the following requirements (new requirements are in green, bold italic font):
- Should return the class code as the classification
- Should make sure the class code is supplied (is not null)
- Should get the description for the class, based on the following table
You must use a switch statement to get the results
| Class Code | Description |
|---|---|
| A | Compressed Gas |
| B | Flammable and Combustible Material |
| C | Oxidizing Material |
| D | Poisonous and Infectious Material |
| E | Corrosive Material |
| F | Dangerously Reactive Material |
- Should override the ToString() method to get the full description and class code in the following format:
- “Class ClassCode - Description”
Use the following class diagram when creating your solution.
CanadianAddress + Province
The CanadianAddress class is modified to now use a ProvinceType enumeration to properly capture the provinces and territories of Canada.
Problem Statement
Modify the CanadianAddress class to now use an enumeration for the province. Use the following class diagram as a guide in creating the class and the enumeration.
Employee/Student + CanadianAddress + Province
The Employee and Student classes now have address information.
Problem Statement
Modify the Employee and Student classes to now use the CanadianAddress type for their addresses.
Company + Month + CanadianAddress + Province
The Company now has a CanadianAddress.
Problem Statement
Modify the Company class to now make use of the CanadianAddress type for the address. Also, create an enumeration for the months of the year for representing the company’s fiscal year end.