Question 4: Methods and Control Structures

“Students will be asked to write program code to create objects of a class and call methods, and satisfy method specifications using expressions, conditional statements, and iterative statements.”

This is similar to “Classes,” but the addition of a need to create class objects and methods, satisfying certain method specifications with different processes, is the most relevant to this problem, as it also involves an interface and the application of said interface with particular instances.

Question Description

This question involves the design of an interface, writing a class that implements the interface, and writing a method that uses the interface.

(a) A number group represents a group of integers defined in some way. It could be empty, or it could contain one or more integers.

Write an interface named NumberGroup that represents a group of integers. The interface should have a single contains method that determines if a given integer is in the group. For example, if group1 is of type NumberGroup, and it contains only the two numbers -5 and 3, then group1.contains(-5) would return true, and group1.contains(2) would return false. Write the complete NumberGroup interface. It must have exactly one method.

(b) A range represents a number group that contains all (and only) the integers between a minimum value and a maximum value, inclusive. Write the Range class, which is a NumberGroup. The Range class represents the group of int values that range from a given minimum value up through a given maximum value, inclusive. For example,the declaration

NumberGroup range1 = new Range(-3, 2);

represents the group of integer values -3, -2, -1, 0, 1, 2.

Write the complete Range class. Include all necessary instance variables and methods as well as a constructor that takes two int parameters. The first parameter represents the minimum value, and the second parameter represents the maximum value of the range. You may assume that the minimum is less than or equal to the maximum.

(c) The MultipleGroups class (not shown) represents a collection of NumberGroup objects and isa NumberGroup. The MultipleGroups class stores the number groups in the instance variable groupList (shown below), which is initialized in the constructor.

private List<NumberGroup> groupList;

Write the MultipleGroups method contains. The method takes an integer and returns true if and only if the integer is contained in one or more of the number groups in groupList.

Code

The following code contains the interface and its related class that utilizes it.

// Interface for part (a)
public interface NumberGroup {
    boolean contains (int val);
}

// Class implementing NumberGroup for part (b)
public class Range implements NumberGroup {
    // initial declarations
    private int min;
    private int max;

    // argument constructor
    public Range(int min, int max) {
        this.min = min;
        this.max = max;
    }

    // contains method, as described
    public boolean contains(int val) {
        if (this.min <= val && val <= this.max) {
            return true;
        }
        return false;
    }
}

// Class implementing NumberGroup for part (c)
public class MultipleGroups implements NumberGroup {
    // initial declaration
    private List<NumberGroup> groupList;
    
    // no argument constructor
    public MultipleGroups() {
        this.groupList = new ArrayList<NumberGroup>();
    }

    // contains method, as described
    public boolean contains(int val) {
        for (NumberGroup group : groupList) {
            if (group.contains(val)) {
                return true;
            }
        }
        return false;
    }

    // method needed for testing (adds NumberGroup to groupList)
    public void addGroup(NumberGroup group) {
        this.groupList.add(group);
    }
}

// testing class for demonstration
public class NumGroupTest {
    public static void main(String[] args) {
        // part (a) is implemented in other two parts and thus does not require testing
        // part (b) test: Range object
        System.out.println("Range object test (range from -3 to 2, as described in CB prompt)");
        Range testRange1 = new Range(-3, 2);
        System.out.println("\tTesting contains() method with value -3: " + testRange1.contains(-3));
        System.out.println("\tTesting contains() method with value 0: " + testRange1.contains(0));
        System.out.println("\tTesting contains() method with value 3 (not in range): " + testRange1.contains(3));

        // part (c) test: MultipleGroups object (tested with Range objects)
        System.out.println("MultipleGroups object test (contains ranges from -3 to 2, and from 5 to 8)");
        MultipleGroups testMultipleGroups = new MultipleGroups();
        Range testRange2 = new Range(5, 8);
        testMultipleGroups.addGroup(testRange1);
        testMultipleGroups.addGroup(testRange2);
        System.out.println("\tTesting contains() method with value -2 (contained in first group): " + testMultipleGroups.contains(-2));
        System.out.println("\tTesting contains() method with value 8 (contained in second group): " + testMultipleGroups.contains(8));
        System.out.println("\tTesting contains() method with value 4 (not in either group): " + testMultipleGroups.contains(4));
    }
}

NumGroupTest.main(null);
Range object test (range from -3 to 2, as described in CB prompt)
	Testing contains() method with value -3: true
	Testing contains() method with value 0: true
	Testing contains() method with value 3 (not in range): false
MultipleGroups object test (contains ranges from -3 to 2, and from 5 to 8)
	Testing contains() method with value -2 (contained in first group): true
	Testing contains() method with value 8 (contained in second group): true
	Testing contains() method with value 4 (not in either group): false

Reflection

I hadn’t ever used a fully unique, customized interface before doing this question, but I was able to figure out how interfaces work through my time working with the JPA repository interfaces of our SpringPortfolio projects.

As a result, I knew that, for part (a), I just needed to define the interface with the proper name containing one method with the right integer parameter, as shown below.

public interface NumberGroup {
    boolean contains (int val);
}

As it turns out, interfaces are essentially blueprints for a more involved instance to base its functionality off of, which are seen in the following two parts of the problem.

My only potential confusion in part (b) was whether or not I needed to specify that a parent (interface) method was being “overwritten” if I defined it as intended in the Range class, but remembering JPA repository, I assumed not and was correct. Aside from that, I had to fight my urge to represent the comparison between the minimum, target value, and end like I would mathematically:

this.min <= val <= this.max

This would create an error, as the comparisons must be separate. Once again, I ended up using the && operator.

this.min <= val && val <= this.max

Knowing how to use interfaces at this point, part (c) was extremely easy. The prompt outlines exactly what to include in the class (groupList collection attribute, initialized in constructor, with contains method that checks for containment in all associated number groups).

Having worked with Many-to-Many collections in our projects throughout the year, I knew to simply initialize the groupList as an empty ArrayList and leave adding items to that ArrayList to another method (not required by the question, but needed for testing). I could have made it so that the list and its contents were added as an argument to the constructor, but it made more sense to start it as empty and allow the user to add to the list separately. This is the most common practice for me.

// no argument constructor
public MultipleGroups() {
    this.groupList = new ArrayList<NumberGroup>();
}

Aside from that, I was able to decrease the amount of code by efficiently using the NumberGroup contains method that must be present in all entries of the groupList when iterating through at checking. Doing so also allows for multiple different types of groups to be stored AND examined within the MultipleGroups class, as all must have their own contians method as a result of the interface outline.

for (NumberGroup group : groupList) {
    if (group.contains(val)) {
        return true;
    }
}
return false;

Overall Notes and Reminders

  • Interfaces essentially act as outlines or blueprints for the functionality of a class or set of classes, especially those that can work together.
  • In these College Board FRQ especially but also in general, it’s important to use other methods that have already been created to make an class’s functionality more efficient.
  • If an ArrayList or some sort of list attribute is part of an object’s primary functionality, it should most likely be initialized in the constructor, argument or no-argument.
    • It is most useful to have an addition method to add to it rather than one that entirely overwrites the attribute’s ArrayList.
  • Multiple numerical comparisons cannot be done with the same set of operators.