Assignment 3: Abstracting over Data Definitions; Custom constructors; Accumulators
Goals: Learn to use the String class, practice working with lists. Learn to design methods for complex class hierarchies.
Instructions
This assignment is long. Start early.
the names of classes,
the names and types of the fields within classes,
the names, types and order of the arguments to the constructor,
the names, types and order of arguments to methods, or
filenames,
Make sure you follow the style guidelines that Bottlenose enforces. For now the most important ones are: using spaces instead of tabs, indenting by 2 characters, following the naming conventions (data type names start with a capital letter, names of fields and methods start with a lower case letter), and having spaces before curly braces.
You will submit this assignment by the deadline using the Bottlenose submission system. You may submit as many times as you wish. Be aware of the fact that close to the deadline the system may have a long queue of submissions which means it takes longer for your code to be submitted - so try to finish early.
The submission will be organized as follows:
Homework 3 Problem 1: The Beverages.java file
Homework 3 Problem 2: The Dyes.java file
Homework 3 Problem 3: The Numbers.java file
Examplar: Saturday, January 27th at 9:00pm
Implementations: Tuesday, January 30th at 9:00pm
Problem 1: Abstracting over Data Definitions
In this problem, our data will represent different kinds of drinks you might order at a coffee shop. Each drink has several attributes, some of which are common to them all and some of which differ.
Note: none of these methods are properly implemented. As given in the file, they are all stubs that currently return a dummy value, so the code will compile but not yet work.
Warmup: Download the file and work out the following problems:
Make at least two examples of data for each of the three classes.
Design the isDecaf method for each class. Coffee is never offered decaf; only Rooibos tea is decaffeinated; and milkshakes are always decaffeinated.
Design the method containsIngredient for each class, which determines if a given ingredient has been mixed into the drink.
Design the method format which produces a String showing how the item would appear on a menu. Bubble tea would show the size, then the variety, then the mixins if any in parentheses, such as "24oz Black tea (with boba, milk)" or "16oz Oolong (without mixins)". Commas separate the mixins (but no trailing comma), and if there aren’t any mixins, the format should say "without mixins". Coffees are formatted similarly, as "Hot Arabica americano (with cream, sugar, hazelnut syrup)" or "Iced Robusta demitasse (without mixins)". Milkshakes look like "24oz Haagen-Dasz strawberry (without mixins)" or "32oz JPLicks peach (with sprinkles)".
Once you have finished these methods and are confident that they work properly, save the work you have done to a separate file. Do not submit the code as written so far. The problems below are the main point of this exercise, and it will be helpful for you to preserve the code written so far as a reference against which to compare your revised code below. Again, submit only the work below.
Look at the code and identify all places where the code repeats —
the opportunity for abstraction. Lift the common fields to an abstract class ABeverage, which should implement IBeverage.
Make sure you include a constructor in the abstract class, and change the constructors in the derived classes accordingly. Run the program and make sure all test cases work as before.
For each method that is defined in all three classes decide to which category it belongs:
The method bodies in the different classes are all different, and so the method has to be declared as abstract in the abstract class.
The method bodies are the same in all classes and it can be implemented concretely in the abstract class.
The method bodies are the same for two of the classes, but are different in one class —
therefore we can define the common body in the abstract class and override it in only one derived class.
Hint: You might find that you can abstract more behavior if you design more helper methods...
Now, lift the methods that can be lifted and run all tests again.
Submit your work in a file named Beverages.java.
Problem 2: Working with Custom Constructors, A Look at Equality
When dyers create pigment mixes to dye yarn, they combine amounts (in grams) of red, yellow, blue and black pigments. A perfect recipe for a dye mix ensures the relative amounts of the four colors are appropriate:
Either the weight of black pigment is no more than 5% the weight of the other three colors combined, or the combined weight of the other three colors is no more than 10% the weight of the black pigment. (This is because black is so much darker than the others, so it’s a waste of pigment to have a lot of black and a lot of the other colors at the same time.)
If there’s any yellow at all, then there must be much more yellow than blue: blue must be no more than a tenth of the yellow dye.
Design a DyeRecipe class. The fields should be of type double and represent the weight of the four dye colors in grams. A dye recipe is always scaled such that the total amount of dye is 1g. Provide three constructors for this class:
Your main constructor should take in all of the fields (in the given order) and enforce all above constraints to ensure a perfect dye recipe. When finished, it should contain 1g of dye.
Provide another constructor that takes in the amount of red, yellow and blue dyes, and produces the darkest perfect dye recipe it can (by adjusting the weights as needed, while keeping the black dye weight less than the total other dye weight).
Provide another constructor that takes in two other dye recipes, and produces a perfect dye recipe that is a half-and-half mixture of the two input recipes. If there is too much black dye, you should reduce its amount to the maximum allowable amount. (For instance, combining an all-red mixture with an all-blue mixture should produce a purple mixture. Combining an all-red mixture with an all-black mixture should produce a mix with 1/21 g of black, and 20/21 g of red.)
You should use an IllegalArgumentException with a helpful message if the above constraints cannot be enforced.
Remove as much duplicate code as possible from these constructors. (Hint: you may want a Utils class to help with computing or enforcing some of the constraints.)
Implement the method sameRecipe(DyeRecipe other) which returns true if the same ingredients have the same weights to within 0.001 grams.
Submit your work in a file named Dyes.java.
Problem 3: Playing with lists of numbers
Consider a simple ILoInt with standard empty and cons classes. Design the following methods, and abstract and generalize as much as you can.
The Fibonacci numbers are the sequence of integers 1, 2, 3, 5, 8, 13, ..., and follow the rule \(F_{n+1} = F_{n-1} + F_{n}\). Each pair of adjacent numbers adds to the next one in the sequence (3 + 5 = 8, 5 + 8 = 13, etc.) We could start with two different numbers, though: the Lucas numbers begin 2, 1, 3, 4, 7, ..., but they follow the same rule. In general, any sequence that follows this rule is called Fibonacci-like. Design a method isFibLike that determines if this list of numbers is Fibonacci-like.
The Pell numbers begin 1, 2, 5, 12, 29, ... and follow the rule \(P_{n+1} = P_{n-1} + 2*P_{n}\). Pell-like sequences follow this rule, but can start from any initial numbers. Design a method isPellLike to check if this list of numbers is Pell-like.
The Nega-Fibonacci numbers begin 1, 1, 0, 1, -1, 2, -3, 5, -8, ..., and follow the rule \(N_{n+1} = N_{n-1} - N_{n}\). Nega-Fibonacci-like numbers follow this rule, but can start from any initial numbers. Design the method isNegaFibLike to determine if this list of numbers is nega-Fibonacci-like.
The Jacobsthal numbers begin 0, 1, 1, 3, 5, 11, 21, 43, 85, ..., and follow the rule \(J_{n+1} = 2*J_{n-1} + J_{n}\). Jacobsthal-like numbers follow this rule, but can start from any initial numbers. Design the method isJacobsthalLike to determine if this list of numbers is Jacobsthal-like.
Design a method secondLargestNum to compute the second-largest number in a list of numbers. (Count repeated numbers individually: If the largest number appears twice, count it as the second-largest number also.)
Design a method fifthLargestNum to compute the fifth-largest number in a list of numbers. (Again, count repeated numbers individually.)
Challenging! Design a method mostCommonNum to compute the number that appears most frequently in this list of numbers. (If multiple numbers appear most frequently, any of them is acceptable.)
Challenging! Design a method thirdMostCommonNum to compute the number that appears third-most-frequently. (If multiple numbers appear third-most frequently, any of them is acceptable.)
You may need to design several helper methods, and possibly helper data
definitions. Think through all the parts of this problem before
starting to code —
Submit your work in a file named Numbers.java.
Examplar submissions
For this problem, we are going to to supply an additional submission on Handins. You will write examples and test cases against a placeholder implementation of the classes and interface needed for this problem, and we will run your test cases against multiple implementations: both correct and buggy! Your goal is to write sufficient test cases to distinguish all the correct implementations from all the buggy ones. We call the correct implementations wheat, and the buggy ones chaff: your goal is to separate the wheat from the chaff.
Create a separate project for this tests-only assignment.
Download the lists.zip file and unzip it into your src/ directory: it should create a lists subdirectory with five files in it.
- Create a file ExamplesLoString.java in your src directory, with the following initial contents:
import lists.*; import tester.Tester; class ExamplesLoInt { // your examples go here } You must not modify the supplied Java files: they’re provided only to ensure that your tests match the types expected by our implementations.
You do not need to develop examples for any methods not given by these stubs.
You will submit only the ExamplesLoInt.java file; do not submit the support files we gave you.
The Examplar for this problem will be due before the coding assignment is due; pay close attention to the deadlines!