JMU JMU - Department of Computer Science
Help Tools
Lab: Questions About Information Hiding


Instructions: Answer the following questions one at a time. After answering each question, check your answer (by clicking on the check-mark icon if it is available) before proceeding to the next question.

Getting Ready: Before going any further, you should:

  1. Depending on your development environment, create either a directory or a project for this lab.
  2. Setup your development environment.
  3. Download the following files:
    to an appropriate directory/folder. (In most browsers/OSs, the easiest way to do this is by right-clicking/control-clicking on each of the links above.)

1. Updating a Test Harness: Recall that in an earlier lab you developed a test harness called Test. For this part of the lab you will update that class.
  1. Modify Test.java so that it uses the System.out object rather than the JMUConsole class. (Hint: Use Find/Replace.)
  2. Add a forEqualString() method to the Test class that can be used to test for the equality of an expected String object and an actual String object. What code did you add?


    solution/Test.java (Fragment: forEqualString)
                /**
         * Display an alert if the contents of the actual String object
         * is not not equal to the contents of the expected value String object.
         *
         * @param description  A description of the test
         * @param expected     The expected value
         * @param actual       The actual value
         */
        public static void forEqualString(String description, 
                                          String expected, String actual) {
            if (!expected.equals(actual)) {
                System.out.printf("%s Expected: %s, Actual: %s\n", 
                                  description, expected, actual);
            }
        }
            
    Expand
2. Creating a Simple Class: This part of the lab will give you some more experience creating classes.
  1. Read the design specification for the JMUPhoneNumber class.
  2. Before writing the class, write a class named JMUPhoneNumberDriver that uses the Test class to test the default constructor, setFormat() and toString() methods. (Writing tests before writing the class is called test-driven development or TDD.)


    solution/JMUPhoneNumberDriver.java (Fragment: 0)
            public class JMUPhoneNumberDriver
    {
        public static void main(String[] args)
        {
            JMUPhoneNumber phone;
            String         actual, expected;
            
    
            phone = new JMUPhoneNumber();
    
            phone.setFormat(JMUPhoneNumber.US_OLD);
            expected = "(540) 568-6211";
            actual = phone.toString();
            Test.forEqualString("US_OLD", expected, actual);
    
            phone.setFormat(JMUPhoneNumber.US_NEW);
            expected = "540-568-6211";
            actual = phone.toString();
            Test.forEqualString("US_NEW", expected, actual);
    
            phone.setFormat(JMUPhoneNumber.EUROPE);
            expected = "540.568.6211";
            actual = phone.toString();
            Test.forEqualString("EUROPE", expected, actual);
    
            phone.setFormat(JMUPhoneNumber.JMU);
            expected = "x8-6211";
            actual = phone.toString();
            Test.forEqualString("JMU", expected, actual);
        }
    }
            
    Expand
  3. Implement the default constructor, setFormat() and toString() methods in the JMUPhoneNumber class (based on the SRS).
  4. What code did you write (for the JMUPhoneNumber class)?


    solution/JMUPhoneNumber.java
            /**
     * An encapsulation of a phone number at JMU
     *
     * @author  Prof. David Bernstein, James madison University
     * @version 1.0
     */
    public class JMUPhoneNumber
    {
        private int      areaCode, exchange, extension, format;
        
    
        public static final int   US_OLD = 0;
        public static final int   US_NEW = 1;
        public static final int   EUROPE = 2;
        public static final int   JMU    = 3;
    
        public static final int   OFFICE = 568;
        public static final int   DORM   = 612;
    
        /**
         * Default Constructor
         *
         * Constructs a JMUPhoneNumber with the areaCode set to 540,
         * the exchange set to 568, the extension set to 6211, and the
         * format set to JMU
         */
        public JMUPhoneNumber()
        {
           areaCode  = 540;
           exchange  = 568;
           extension = 6211;
           format    = JMU;       
        }
        /**
         * Returns true iff this JMUPhoneNumber has the same area code,
         * exchange, and extension as the given JMUPhoneNumber.
         *
         * @param other  The JMUPhoneNumber to compare with this one
         * @return true if the two have the same attributes; false otherwise
         */
        public boolean equals(JMUPhoneNumber other)
        {
            return (this.areaCode == other.areaCode) 
                && (this.exchange == other.exchange)
                && (this.extension == other.extension);
        }
        /**
         * Checks if this JMUPhoneNumber is in a dorm
         *
         * @return   true if in a dorm and false otherwise
         */
        public boolean isDorm()
        {
           return (exchange == DORM);       
        }
    
        /**
         * Checks if this JMUPhoneNumber is in an office
         *
         * @return   true if in an office and false otherwise
         */
        public boolean isOffice()
        {
           return (exchange == OFFICE);       
        }
    
        /**
         * Sets the exchange associated with this JMUPhoneNumber
         *
         * Note: If the parameter is not valid this method sets the
         *       exchange to OFFICE
         *
         * @param  exchange   The exchange (either OFFICE or DORM)
         */
        public void setExchange(int exchange)
        {
           if (exchange == DORM) this.exchange = DORM;       
           else                  this.exchange = OFFICE;       
        }
    
        /**
         * Sets the extension associated with this JMUPhoneNumber
         *
         * Note: If the parameter is not valid this method sets the
         *       extension to 6211
         *
         * @param  extension   The extension (between 0000 and 9999)
         */
        public void setExtension(int extension)
        {
           if ((extension >= 0) && (extension <= 9999))
              this.extension = extension;
           else
              this.extension = 6211;       
        }
        /**
         * Sets the format to be used by the toString method
         *
         * The valid formats along with examples are:
         *
         *    US_OLD   (540) 568-6211
         *    US_NEW   540-568-6211
         *    EUROPE    540.568.6211
         *    JMU       x8-6211
         *
         * Note: If the parameter is not valid this method sets the
         *       format to JMU
         *
         * @param  format   A valid format
         */
        public void setFormat(int format)
        {
           if      (format == US_OLD) this.format = US_OLD;
           else if (format == US_NEW) this.format = US_NEW;
           else if (format == EUROPE)  this.format = EUROPE;
           else                        this.format = JMU;       
        }
    
        /**
         * Returns a formatted String representation of this JMUPhoneNumber
         * (see the discussion of the setFormat method)
         */
        public String toString()
        {
           String      fourDigitExtension, result;
           
           fourDigitExtension = String.format("%04d",extension);       
           
           result = "";
    
           if      (format == US_OLD)
           {
              result = "("+areaCode+") "+exchange+"-"+fourDigitExtension;
           }
           else if (format == US_NEW)
           {
              result = areaCode+"-"+exchange+"-"+fourDigitExtension;          
           }
           else if (format == EUROPE)
           {
              result = areaCode+"."+exchange+"."+fourDigitExtension;          
           }
           else if (format == JMU)
           {
              if      (exchange == OFFICE) result = "x8-";
              else if (exchange == DORM)   result = "x2-";
    
              result += fourDigitExtension;          
           }
    
           return result;       
        }
    }
            
    Expand
  5. Test these methods using your driver.
  6. One method at a time, implement and test the rest of the JMUPhoneNumber class.
  7. What code did you add to the JMUPhoneNumber class?


    solution/JMUPhoneNumber.java (Fragment: 1)
                /**
         * Checks if this JMUPhoneNumber is in a dorm
         *
         * @return   true if in a dorm and false otherwise
         */
        public boolean isDorm()
        {
           return (exchange == DORM);       
        }
    
        /**
         * Checks if this JMUPhoneNumber is in an office
         *
         * @return   true if in an office and false otherwise
         */
        public boolean isOffice()
        {
           return (exchange == OFFICE);       
        }
    
        /**
         * Sets the exchange associated with this JMUPhoneNumber
         *
         * Note: If the parameter is not valid this method sets the
         *       exchange to OFFICE
         *
         * @param  exchange   The exchange (either OFFICE or DORM)
         */
        public void setExchange(int exchange)
        {
           if (exchange == DORM) this.exchange = DORM;       
           else                  this.exchange = OFFICE;       
        }
    
        /**
         * Sets the extension associated with this JMUPhoneNumber
         *
         * Note: If the parameter is not valid this method sets the
         *       extension to 6211
         *
         * @param  extension   The extension (between 0000 and 9999)
         */
        public void setExtension(int extension)
        {
           if ((extension >= 0) && (extension <= 9999))
              this.extension = extension;
           else
              this.extension = 6211;       
        }
            
    Expand
  8. What code did you add to the driver?


    solution/JMUPhoneNumberDriver.java (Fragment: 1)
                    // Valid DORM exchange
            phone.setExchange(JMUPhoneNumber.DORM);        
            Test.forTrue("Valid DORM - isDorm()", phone.isDorm());
            Test.forFalse("Valid Dorm - isOffice()", phone.isOffice());
            expected = "x2-6211";
            actual = phone.toString();
            Test.forEqualString("JMU Dorm", expected, actual);
            
            // Invalid exchange
            phone.setExchange(999);        
            Test.forFalse("Invalid Exchange - isDorm()", phone.isDorm());
            Test.forTrue("Invalid Exchange - isOffice()", phone.isOffice());
            expected = "x8-6211";
            actual = phone.toString();
            Test.forEqualString("JMU DORM", expected, actual);
    
            // Valid OFFICE exchange
            phone.setExchange(JMUPhoneNumber.OFFICE);        
            Test.forFalse("Valid OFFICE - isDorm()", phone.isDorm());
            Test.forTrue("Valid OFFICE - isOffice()", phone.isOffice());
            expected = "x8-6211";
            actual = phone.toString();
            Test.forEqualString("JMU OFFICE", expected, actual);
            
            // Invalid Extension
            phone.setExtension(-1);
            expected = "x8-6211";
            actual = phone.toString();
            Test.forEqualString("Invalid Extension (0)", expected, actual);
    
            phone.setExtension(10000);
            expected = "x8-6211";
            actual = phone.toString();
            Test.forEqualString("Invalid Extension (10000)", expected, actual);
    
            // Valid Extension
            phone.setExtension(1234);
            expected = "x8-1234";
            actual = phone.toString();
            Test.forEqualString("Valid Extension", expected, actual);
    
    
            
    Expand
  9. Make sure that you KEEP THIS CLASS and the driver. You'll need them for other labs.
3. Review: This part of the lab will help you remember some important things about creating classes.
  1. Your setExchange() method should look like the following:
      public void setExchange(int exchange)
      {
          this.exchange = exchange;
      }
    

    If not, fix it.

  2. What happens (when you compile and/or execute your code) if you change it to the following?
      public void setExchange(int exchange)
      {
          exchange = exchange;
      }
    


    It compiles but when executed the attribute named exchange is not changed. The parameter named exchange has its value assigned to it (i.e., it doesn't change either).
    Expand
  3. What happens (when you compile and/or execute your code) if you change it to the following?
      public void setExchange(int exchange)
      {
          exchange = this.exchange;
      }
    


    It compiles but when executed the attribute named exchange is not changed. The value of the attribute named exchange is assigned to the parameter named exchange but, since parameters are passed by value in Java, this has no impact outside of this method.
    Expand
  4. What happens (when you compile and/or execute your code) if you change it to the following?
      public void setExchange(int this.exchange)
      {
          exchange = this.exchange;
      }
    


    It does not compile.
    Expand
  5. What happens (when you compile and/or execute your code) if you change it to the following?
      public void setExchange(int exchange)
      {
          this.exchange = this.exchange;
      }
    


    It compiles and the value of the attribute named exchange is assigned to the attribute named exchange. Which is to say, it doesn't change.
    Expand
  6. Change your setExchange() method back to:
      public void setExchange(int exchange)
      {
          this.exchange = exchange;
      }
    
4. The Benefits of Information Hiding: This part of the lab will help you understand some of the benefits of information hiding.
  1. In your driver, after declaring and constructing a JMUPhoneNumber named csOffice, add the following line:
          csOffice.extension = 2745;
    
  2. Compile your driver.
  3. What happens?


    The driver does not compile.
    Expand
  4. Remove the offending code from your driver.
  5. What is gained by making the areaCode, exchange, and extension private?


    It prevents invalid area codes and exchanges.
    Expand
  6. What is gained by making isDorm and isOffice public methods rather than public attributes?


    Consistency is maintained. In other words, it prevents the two attributes from both being true or both being flase (which, obviously, doesn;t make sense).
    Expand
  7. Should the toString() method create a String each time it is called, or should it return an attribute?


    This is an important question to ask about many accessors (and related methods). In general, you can "do the work" every time the method is called or you can "do the work" only when something changes. There are advantages and disadvantages to both, and you need to think about the details of the situation in each case.

    In this case, I would create a String each time the toString() method is called. Though this means "the work" is being done multiple times, even if the attributes haven't changed, I think that is a cost that is worth incurring.

    If you do it the other way, the attribute containing the String representation will have to be modified every time the setFormat(), setExchange(), and setExtension() methods are called. In my opinion, this would be prone to errors.

    Expand
  8. Suppose you return an attribute in the toString() method. Should the attribute be public or private? Why?


    It should definitely be private. Otherwise the String could be changed outside of the class (and be inconsistent with the desired format).
    Expand
  9. Why would it be useful to have a method named equals() in the JMUPhoneNumber class?


    Because we might want to compare two JMUPhoneNumber objects and the == operator only compares references.
    Expand
  10. Why is it better to have a method named equals() than to have accessors for all of the attributes?


    Because there is no reason for anyone else to know the details of JMUPhoneNumber objects. Again, this is an important aspect of information hiding.
    Expand
  11. Should the equals() method compare the format?


    I don't think so. The format is not really an intrinsic attribute of JMUPhoneNumber objects. However, even if you decide otherwise, this is not something that anyone other than the designer of the class should have to think about (i.e., it is an internal detail that should be hidden).
    Expand
  12. Implement the equals() method. What code did you add?


    solution/JMUPhoneNumber.java (Fragment: equals)
                /**
         * Returns true iff this JMUPhoneNumber has the same area code,
         * exchange, and extension as the given JMUPhoneNumber.
         *
         * @param other  The JMUPhoneNumber to compare with this one
         * @return true if the two have the same attributes; false otherwise
         */
        public boolean equals(JMUPhoneNumber other)
        {
            return (this.areaCode == other.areaCode) 
                && (this.exchange == other.exchange)
                && (this.extension == other.extension);
        }
            
    Expand
  13. Add one or more tests to your JMUPhoneNumberDriver class that test the equals() method. What code did you add?


    solution/JMUPhoneNumberDriver.java (Fragment: equals)
                    // equals()
            JMUPhoneNumber a, b, c, d, e;
            a = new JMUPhoneNumber();
            b = new JMUPhoneNumber();
            Test.forTrue("equals() - Same", a.equals(b));
            
            c = new JMUPhoneNumber();
            c.setExchange(JMUPhoneNumber.DORM);
            Test.forFalse("equals() - Different Exchange", a.equals(c));
            
            d = new JMUPhoneNumber();
            d.setExtension(1234);
            Test.forFalse("equals() - Different Extension", a.equals(d));
            
            e = new JMUPhoneNumber();
            e.setExchange(JMUPhoneNumber.DORM);        
            e.setExtension(8888);
            Test.forFalse("equals() - Different Both", a.equals(e));
            
    Expand
  14. Why are the "constants" in the JMUPhoneNumber class declared to be public?


    So that they can be used in other classes (without having to know their values).
    Expand
  15. Why isn't it a problem that the "constants" are declared to be public?


    Because they are also declared to be final. So, they can't be "damaged".
    Expand
  16. Given that the JMUPhoneNumber class has a setExtension() method, some people would argue that the extension attribute should be made public. Why is this argument not even slightly compelling?


    Because the class does not have a getExtension() method. So, making the extension attribute public would change the functionality provided by the class.
    Expand
  17. Suppose the JMUPhoneNumber class also had a getExtension() method. Would you then argue that the extension attribute should be public?


    No. Notice that the setExtension() method prevents the caller from assigning a nonsensical value to the extension attribute. If the extension attribute were public, it could be assigned any int value (even one that isn't a valid extension).
    Expand
5. Other Questions: This part of the lab will help you think about some other important issues that arise when designing/developing classes.
  1. Why is it a good idea to make immutable attributes final even when they are private and the class does not include any public mutators?


    Because then they can't be changed inadvertently by other methods in the class.
    Expand
  2. Why would it be useful to have a method named parseString() that converts a String representation (e.g., "540-568-1671") to a JMUPhoneNumber?


    Because it is much easier to ask people to enter a phone number as a String?
    Expand
  3. Should such a parseString() method belong to the String class or the JMUPhoneNumber class?


    The JMUPhoneNumber class. Otherwise, the String class would have to know about all possible classes and their String representations.
    Expand
  4. An auto-dialer iteratively calls all of the phone numbers at a location. How would you implement a next() method that would facilitate this?


    It would increase the extension by 1 (until it got to 9999), construct a new JMUPhoneNumber with that extension, and then return it. If the increased extension is greater than 9999 it needs to use the next exchange (if there is one) and make the extension 0001.
    Expand
  5. Are JMUPhoneNumber objects mutable or immutable?


    They are mutable since their attributes can be changed.
    Expand
  6. Should JMUPhoneNumber objects be mutable or immutable?


    The answer to this question depends on how they are going to be used. I think that, in most cases, they should probably be immutable. However, if a JMUPhoneNumber was being used in an application in which it was an attribute of a phone, you might want it to be mutable (since phone numbers can change). This is a question that will be discussed in more detail in other courses.
    Expand

Copyright 2019