SDSU CS 535 Object-Oriented Programming & Design
Spring Semester, 1999
Comments on the Programs
Previous    Lecture Notes Index        
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 11-May-99

Contents of Doc 20, Comments on the Programs


References

Various student papers

Doc 20, Comments on the Programs Slide # 2

Names


IFYOUUSECAPITALLETTERSYOUNEED
TO_ADD_SOMETHING_TO_SEPARATE_WORDS

How Useful are these Names?
fileName
delimiter

Code Presentation


Tabs and spaces do not mix well

If you use tabs to indent your code, then always use tabs. By always I mean every line of code in your program uses tabs and no spaces for indentation.
If you use spaces always use spaces and always use the same number of spaces.

Indentation is important for readability.

Be consistent!

if (x == y )
   {
   if (z == w )
      blah
else
   whereDoesThisGo?
   }

Doc 20, Comments on the Programs Slide # 3

Documentation


public class Translator
   {
   HashMap dictionary = new HashMap();

public void addWords(String key, String words )
   {
   Vector words = new Vector();
   StringTokenizer parser = new StringTokenizer( words, "," );
   while (parser.hasMoreTokens)
      {
      String word = parser.nextToken();
      words.add( word);
      }
   
   dictionary.put( key, words );
   }
The argument "words" to addWords must be properly formatted

Don’t make the reader read the method to find out that it must be formatted and what the format is.

The field "dictionary" requires a vector as a value.

Don’t make the reader read the entire class to find that out

If you use files that contain formatted data, document the format in the file and in the code, give examples.

Doc 20, Comments on the Programs Slide # 4

Parameters verses Fields


Avoid using fields as implicit parameters to methods in the same class. Explicit parameters make the dependency clear.

public class Translator
   {
   private String aValue;
   public void bar()
      {
      blah;
      blah;
      aValue = result of some computation;
      foo();
      more blah;
      }
   private void foo()
      {
      String myData = aValue;
      Compute on myData;
      }
   }

Doc 20, Comments on the Programs Slide # 5

Java’s Return Problems


Goal
Given a method isValid( String value ) we want to return two pieces of information:
Boolean result
If it is not valid a reason

Problem
Java supports only one return type
Java supports only pass-by-value

So the following will not work:

boolean isValid( String value, String reasonInvalid )
   {
   if ( value is not valid )
      {
      reasonInvalid = "A reason";
      return false;
      }
   else
      return true;
   }


Doc 20, Comments on the Programs Slide # 6
Do not be tempted to do the following:

public class Foo
   {
   private String reasonInvalid;
   
   public boolean isValid( String value )
      {
      if ( value is not valid )
         {
         reasonInvalid = "A reason";
         return false;
         }
      else
         return true;
      }
   
   public String getReason()
      {
      return reasonInvalid;
      }
   }

Doc 20, Comments on the Programs Slide # 7
What are the solutions?

Use two methods

public class Foo
   {   
   public boolean isValid( String value )
      {
      if ( reasonNotValid( value ) == null )
         return true;
      else
         return false;
      }
   
   public String reasonNotValid( String value )
      {
      if ( value == null )
         return "null not allowed" ;
      else if ( value.length() == 0 )
         return "empty strings not allowed";
      else
         return null;
      }
   }


Doc 20, Comments on the Programs Slide # 8
Pass in an object to hold the reason

public class Foo
   {   
   public boolean isValid( String value, Reason explain )
      {
      if ( value == null )
         {
         explain.text = "null not allowed";
         return false ;
         }
      else if ( value.length() == 0 )
         {
         explain.text = "empty strings not allowed";
         return false ;
         }
      else
         return true;
      }
   }

Doc 20, Comments on the Programs Slide # 9
Throw Exceptions

public class Foo
   {   
   public void validate( String value)
      {
      if ( value == null )
         throw new NotValidException( "null not allowed");
      else if ( value.length() == 0 )
         throw new NotValidException( "empty strings not allowed");
      }
   }
This should not be used too often.

Doc 20, Comments on the Programs Slide # 10

Some Translator Solutions


We need to deal with one and two step translations

One step translations
English to German
Spanish to English
Two step translations
Spanish to English to German

How to do this without lots of if statements?


Doc 20, Comments on the Programs Slide # 11
Interface solution

public interface Translatable
   {
   public String translate( String word );
   public boolean contains( String word );
   }
public class OneStepTranslation implements Translatable
   {
   HashMap dictionary = new HashMap( );
   
   public String translate( String word )
      {
      return (String) dictionary.get( word );
      }
   public boolean contains( String word )
      {
      return dictionary.containsKey( word );
      }
   
   }

Doc 20, Comments on the Programs Slide # 12
public class TwoStepTranslation implements Translatable
   {
   OneStepTranslation foreignToEnglish = new OneStepTranslation( );
   OneStepTranslation englishToForeign = new OneStepTranslation( );
   
   public String translate( String word )
      {
      String englishTranslation = foreignToEnglish.translate( word);
      return englishToForeign.translate( word );
      }
   public boolean contains( String word )
      {
      if (! foreignToEnglish.contains( word ) )
         return false;
      String englishTranslation = foreignToEnglish.translate( word);
      return englishToForeign.contains( englishTranslation );
      }
   }
Now the Translator class can use Translatables
It only has to create the correct type originally

Doc 20, Comments on the Programs Slide # 13
A Second SolutionWord
This class represents a word with its translations into multiple languages

public class Word
   {
   /**
    * Keys = languages as strings
    * Values = Set of strings, each string is a translation
          of this word into the give language
    */
   HashMap translations = new HashMap();
   public boolean containsLanguage( String language )
      {
      return translations.containsKey( language );
      }
   public Set translateTo( String language )
      {
      return (Set) translations.get( language );
      }
   public void addTranslation( String language, String text )
      {
      String[] newTranslation = { text };
      addTranslations( language, newTranslation );
      }
   public void addTranslations( String language, String[] text )
      {
      if ( !containsLanguage( language ) )
         translations.put( language, new TreeSet() );
      Set existingTranslations = (Set) translations.get( language );
      List newTranslations = Arrays.asList( text );
      existingTranslations.addAll( newTranslations );
      }
   
   public Set languages()
      {
      return translations.keySet();
      }
   }

Doc 20, Comments on the Programs Slide # 14
WordIndex
The class represents an index of words objects. The index maps language - word translations pairs (Spanish, madre) to word objects.

public class WordIndex
   {
   /**
     * keys = Strings of the format lanuage@text. For
              example english@mother
     * Values = Word objects that contains translation of the text
              into other languages
     */
   TreeMap languageWordIndex = new TreeMap();
   
   private static final String LANGUAGE_TEXT_SEPARATOR = "@";
   
   public void add( Word newWord )
      {
      Set languageSet = newWord.languages();
      
      Iterator languages = languageSet.iterator();
      
      while ( languages.hasNext() )
         {
         String language =  (String) languages.next();
         add( language, newWord );
         }
      }
   
   public boolean contains( String language, String text )
      {
      return languageWordIndex.containsKey( key( language, text ));
      }
      
   public Word get( String language, String text )
      {
      return (Word) languageWordIndex.get( key( language, text ));
      }
   
   private static String key( String language, String text )
      {
      return language.toLowercase().trim() + 
         LANGUAGE_TEXT_SEPARATOR + 
         text.toLowercase().trim();
      }
      
   private void add( String language, Word newWord )
      {
      Set translationSet = newWord.translateTo( language );
      
      Iterator translations = translationSet.iterator();
      while ( translations.hasNext() )
         {
         String aTranslation = (String) translations.next();
         languageWordIndex.put( key( language, aTranslation), 
                                    newWord);
         }
      }
   }

Doc 20, Comments on the Programs Slide # 15
Translator Class

Now the translator class can contain a WordIndex. The index is used to look up words.

Copyright ©, All rights reserved.
1999 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.

Previous    visitors since 11-May-99