SDSU CS 635 Advanced Object-Oriented Design & Programming
Spring Semester, 2001
Assignment 1 Comments
Previous    Lecture Notes Index    Next    
© 2001, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 10-Apr-01

Contents of Doc 15, Assignment 1 Comments


References

Code Complete, McConnell, Microsoft Press, 1993

Refactoring: Improving the Design of Existing Code, Fowler, Addison Wesley Longman, 1999


Doc 15, Assignment 1 Comments Slide # 2

Standard Issues

Consistency

There is a lot of flexibility in the coding styles

Be consistent

Example

In Java you can declare fields anywhere in the class

Most people put them either at the begging or end of a class

Pick one location and always do it.

Example

public void foo()
{
   code here
}

public void bar() { code here }

public void foobar() {
   code here
}


Doc 15, Assignment 1 Comments Slide # 3

Code formatting


Indentation is important
Alignment is important


public abstract class HttpTransaction
 {
 HashMap headers = new HashMap();
 byte[] body;
     abstract void  parseFirstLine(ByteReader input ); q 
 abstract String firstLineToString();
   public void fromStream( InputStream input) throws IOException
 {
  ByteReader bufferedInput = new ByteReader( input);
      
parseFirstLine(bufferedInput);
if ( hasHeaders() )
parseHeaders(bufferedInput);
if (hasBody() )
parseBody(bufferedInput);
}
      
   public byte[] toBytes()
    {
   if (!hasBody())
       return toString().getBytes();
      String headerString = toString();
     int length = headerString.length() + body.length;
      byte[]  transaction = new byte[length];  
     System.arraycopy(headerString.getBytes(), 0, transaction, 0, headerString.length());
         System.arraycopy(body, 0, transaction, headerString.length(), body.length);
    return transaction;
      }
      
   public boolean hasContentLength()
      {
      return (headers.containsKey( "Content-length" ) || 
         headers.containsKey( "Content-Length" ));
      } 



Doc 15, Assignment 1 Comments Slide # 4

Line Wrap


Just say no to line wrap in source code

   public byte[] toBytes()
      {
      if (!hasBody())
         return toString().getBytes();      //get the string and 
convert it to bytes then return it
      String headerString = toString();//convert to a string
      int length = headerString.length() +
 body.length;
      byte[]  transaction = new byte[length];//declare transaction
      System.arraycopy(headerString.getBytes(), 0, 
transaction, 0, headerString.length());
      System.arraycopy(body, 0, transaction, 
headerString.length(), body.length);
      return transaction;
      }
         {
         String requestLine = readLine(input);      // Read a 
Line of input from the input
         while (requestLine.length() > 0 )
            {
            int separatorIndex = requestLine.indexOf(':');
            String name = requestLine.substring(0, 
separatorIndex);
            String value = 
requestLine.substring(separatorIndex + 1).trim();
            headers.put( name, value);
            requestLine = readLine(input);

Doc 15, Assignment 1 Comments Slide # 5
What Causes Line wrap

End of line comments

         String requestLine = readLine(input);      // Read a 
Line of input from the input

Solution



Long Variable Names

IfYouHaveReallyLongVariableNames they will cause line wrap

ReallyLongVariableNamesAreHardToRead

Solution



Doc 15, Assignment 1 Comments Slide # 6
Nesting and Line Wrap

Nesting code can cause line wrap

if ( blah ) {
   if (more blah) {
      foo;
   else {
      if ( bar ) {
         not bar
      else {
         if ( more bar ) {
            if (even more bar ) {
               if (still more bar ) {
                  if (even still more bar ) {
                     if ( bar until you can’t stand it ) {
                        if ( foo ) {
                           if ( more foo ) {
                              if ( still more foo ) {
                                 if ( you can understand the nesting level here please do not work for me) {
                                 }
                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }

Doc 15, Assignment 1 Comments Slide # 7
Nesting levels

Don't go deep.



Doc 15, Assignment 1 Comments Slide # 8

Refactorings to reduce nesting levels

Replace Nested Conditional with Guard Clauses[1]


A method has conditional behavior that does not make clear the normal path of execution

Use guard clauses for all the special cases

double getPayAmount() {
   double result;
   if ( _isDead) 
      result = deadAMount();
   else {
      if ( _isSeparated) 
         result = separatedAmount();
      else {
         if (_isRetired) 
            result = retiredAmount();
         else
            result = normalPayAmount();
      }
   }
}

double getPayAmount() {
   if ( _isDead) 
      return deadAMount();
   if ( _isSeparated) 
      return separatedAmount();
   if (_isRetired) 
      return  retiredAmount();
   return normalPayAmount();
}


Doc 15, Assignment 1 Comments Slide # 9

Decompose Conditional[2]


You have a complicated conditional (if-then-else) statement

Extract methods from the condition, then part and else parts

Example[3]

   if (date.before (SUMMER_START) || date.after(SUMMER_END))
      charge = quality * _winterRate + _winterServiceCharge;
   else
      charge = quantity * _summerRate

becomes

   if (notSummer( date))
      charge = winterCharge(quantity);
   else
      charge = summerCharge(quantity);

Doc 15, Assignment 1 Comments Slide # 10

Introduce Null Object[4]


You have repeated checks for a null value

Replace the null value with a null object

Example

void add(int key, String value)
   if (key < _key ) {
      if (right == null)
         left == new BinaryNode(key, value);
      else
         left .add( key, value);
      etc.

Use a NullNode object that has a pointer to its parent

The NullNode add(key,value) method adds a new subtree to its parent

Then we get:

void add(int key, String value)
   if (key < _key ) {
      left .add( key, value);
      etc.


Doc 15, Assignment 1 Comments Slide # 11
An Example
void add(int key, String value)
   if (key < _key ) {
      if (left == null)
         left = new BinaryNode(key, value);
      else
         left.add( key, value);
   else {
      if (key == _key )
         value = _value;
      else {
         if (key > _key ) {
            if ( right == null ) {
               right = new BinaryNode(key, value);
            else
               left.add( key, value);
         }
      }
   }
}
Applying the above ideas this becomes

void add(int key, String value)
   if (key < _key )
      retun left.add( key, value);
   if (key == _key )
      return value = _value;
   if (key > _key ) 
      return left.add( key, value);
}


Doc 15, Assignment 1 Comments Slide # 12

Comments


"Comments are easier to write poorly than well, and comments can be more damaging than helpful"
What does this do?

for i := 1 to Num do
 MeetsCriteria[ i ] := True;
for  i := 1 to Num / 2  do begin
 j := i + i;
 while ( j <= Num ) do begin
  MeetsCriteria[ j ] := False;
  j := j + i;
 end;
for i := 1 to Mun do
 if MeetsCriteria[ i ] then
  writeln( i, ' meets criteria ' );


Doc 15, Assignment 1 Comments Slide # 13
How many comments does this need?

for PrimeCandidate:= 1 to Num do
   IsPrime[ PrimeCandidate] := True;
for  Factor:= 1 to Num / 2  do begin
   FactorableNumber := Factor + Factor ;
   while ( FactorableNumber <= Num ) do begin
      IsPrime[ FactorableNumber ] := False;
      FactorableNumber := FactorableNumber + Factor ;
   end;
end;
for PrimeCandidate:= 1 to Num do
   if IsPrime[ PrimeCandidate] then
      writeln( PrimeCandidate, ' is Prime ' );
Good Programming Style is the Foundation of Well Commented Program


Doc 15, Assignment 1 Comments Slide # 14

Kinds of Comments



   X := X + 1    /* add one to X
   /** Integer value */
   private int key;
   /** String value */
   private String value;

Used to explain complicated or tricky code
      *p++->*c = a
      /* first we need to increase p by one, then ..
Make code simpler before commenting
      (*(p++))->*c = a
      ObjectPointerPointer++;
      ObjectPointer = *ObjectPointerPointer;
      ObjectPointer ->*DataMemberPointer = a;


Doc 15, Assignment 1 Comments Slide # 15

/*  **** Need to add error checking here  **** */


Distills a few lines of code into one or two sentences

Explains the purpose of a section of code

{ get current employee information }   intent
{ update EmpRec structure }     what


Doc 15, Assignment 1 Comments Slide # 16

Commenting Efficiently



/***********************************
 * module: Print                   *
 *                                 *
 * author: Roger Whitney           *
 * date:   Sept. 10, 1995          *
 *                                 *
 * blah blah blah                  *
 *                                 *
 ***********************************/
/***********************************
  module: Print          
                         
  author: Roger Whitney  
  date:   Sept. 10, 1995 
                         
  blah blah blah         
                         
 ***********************************/


Doc 15, Assignment 1 Comments Slide # 17

Commenting Techniques

Commenting Individual Lines


Avoid self-indulgent comments
MOV AX,  723h        ;    R. I. P. L. V. B.



Endline comments have problems


MemToInit := MemoryAvailable(); { get memory available }


Not much room for comment
Must work to format the comment



Use endline comments on

Data declarations
Maintenance notes
Mark ends of blocks


Doc 15, Assignment 1 Comments Slide # 18

Commenting Paragraphs of Code


Write comments at the level of the code's intent

Comment the why rather than the how

Make every comment count

Document surprises

Avoid abbreviations

How verses Why

How
/* if allocation flag is zero */
if ( AllocFlag == 0 ) ...


Why
/* if allocating a new member */
if ( AllocFlag == 0 ) ...


Even Better
/* if allocating a new member */
if ( AllocFlag == NEW_MEMBER ) ...


Doc 15, Assignment 1 Comments Slide # 19
Summary comment on How

{ check each character in "InputStr" until a 
  dollar sign is found or all characters have 
  been checked }
Done   := false;
MaxPos := Length( InputStr );
i      := 1;
while ( (not Done) and (i <= MaxLen) ) begin
   if ( InputStr[ i ] = '$' ) then
      Done := True
   else
      i := i + 1
end;
Summary comment on Intent

{ find the command-word terminator }
Done   := false;
MaxPos := Length( InputStr );
i      := 1;
while ( (not Done) and (i <= MaxPos ) ) begin
   if ( InputStr[ i ] = '$' ) then
      Done := True
   else
      i := i + 1
end;


Doc 15, Assignment 1 Comments Slide # 20
Summary comment on Intent with Better Style

{ find the command-word terminator }
FoundTheEnd      := false;
MaxCommandLength := Length( InputStr );
Index            := 1;
while ((not FoundTheEnd) and 
       (Index <= MaxCommandLength)) begin
   if ( InputStr[ Index ] = '$' ) then
      FoundTheEnd := True;
   else
      Index := Index + 1;
end;


Doc 15, Assignment 1 Comments Slide # 21

Commenting Data Declarations


Comment the units of numeric data

Comment the range of allowable numeric values

Comment coded meanings

var
   CursorX:      1..MaxCols;   { horizontal screen position of cursor }
   CursorY:      1..MaxRows;   { vertical position of cursor on screen }
   AntennaLength:   Real;   { length of antenna in meters: >= 2 }
   SignalStrength:   Integer;   { strength of signal in kilowatts: >= 1 }
   CharCode:      0..255;   { ASCII character code }
   CharAttib:      Integer;   { 0=Plain; 1=Italic; 2=Bold  }
   CharSize:         4..127;   { size of character in points }
Comment limitations on input data
Document flags to the bit level


Doc 15, Assignment 1 Comments Slide # 22

Commenting Routines


Avoid Kitchen-Sink Routine Prologs

Keep comments close to the code they describe

Describe each routine in one or two sentences at the top of the routine

Document input and output variables where they are declared

Differentiate between input and output data

Document interface assumptions

Keep track of the routine's change history

Comment on the routine's limitation

Document the routine's global effects

Document the source of algorithms that are used

procedure InsertionSort 
   {
   Var   Data:      SortArray;    { sort array elements }
      FirstElement:   Integer        {index of first element to sort}
      LastElement:   Integer        {index of last element to sort}
   }


Doc 15, Assignment 1 Comments Slide # 23
Comments From Hell

//*****************************************************
//*****************************************************
// Class: Proxy
//*****************************************************
//*****************************************************
public class Proxy {
   //***************************************************
   //Default Constructor
   //***************************************************
   public Proxy() { blah }
   //***************************************************
   //Constructor
   //***************************************************
   public Proxy(int size) {
   _size = size;}
   //***************************************************
   //Main
   //***************************************************
   public static void public static void main( String[] args ) {
      //Create a new socket
      ServerSocket acceptor = new ServerSocket(0);
      //Print out the port number
      System.out.println("On port " + acceptor.getLocalPort());
      while (true) {//runs forever, until program is manually killed
         Socket client = acceptor.accept();//Accept a new connection
         processRequest(//Process the client request 
            client.getInputStream(),//get the input
            client.getOutputStream());//get the ouput
         client.close();//Close the connection


Doc 15, Assignment 1 Comments Slide # 24
Less is Better

public class Proxy 
   {

   public Proxy() 
      { 
      blah 
      }

   public Proxy(int size) 
      {
      _size = size;
      }

   public static void public static void main( String[] args ) 
      {
      ServerSocket acceptor = new ServerSocket(0);
      System.out.println("On port " + acceptor.getLocalPort());

      //Must kill process to terminate
      while (true) 
         {
         Socket client = acceptor.accept();
         processRequest( 
            client.getInputStream(),
            client.getOutputStream());
         client.close();
         }
      }
   }


Doc 15, Assignment 1 Comments Slide # 25
If you really need to separate Sections

//-------------------------------------------------------------

public class Proxy 
   {

   public Proxy() 
      { 
      blah 
      }

   public Proxy(int size) 
      {
      _size = size;
      }

   public static void public static void main( String[] args ) 
      {
      ServerSocket acceptor = new ServerSocket(0);
      System.out.println("On port " + acceptor.getLocalPort());

      //Must kill process to terminate
      while (true) {
         Socket client = acceptor.accept();
         processRequest( 
            client.getInputStream(),
            client.getOutputStream());
         client.close();


Doc 15, Assignment 1 Comments Slide # 26
Names
Use the Java standard

thisIsTheJavaStandardNameStyleForMethodNamesAndVariables

ClassName

STATIC_FINAL

"Finding good names is the hardest part of OO Programming"

"Names should fully and accurately describe the entity the variable represents"

What role does the variable play in the program?


Examples in Assignment

s
r
l
temp
BSIterator
BST
stk

Doc 15, Assignment 1 Comments Slide # 27
Coupling

public Interator interator(int order) 
   {
   switch(order)
      {
      case PREORDER:
         return new PreorderInterator(this);
      case INORDER:
         return new InorderInterator(this);
      default:
         throw new IllegalArgumentExeption("No such order");
      }
   }

Verses:

public Interator preorderInterator() 
   {
   return new PreorderInterator(this);
   }

public Interator inorderInterator() 
   {
   return new InorderInterator(this);
   }


Doc 15, Assignment 1 Comments Slide # 28
Repeated Fields

abstract class Visitor
   {
   Node root;
   abstract void visitTree(BinaryTree visitee);
   abstract void visitNode(Node visitee);
   }

class PreorderVisitor extends Visitor
   {
   Node root;
   blah
   etc.
   }

This is asking for trouble

Just say no to repeated fields

Doc 15, Assignment 1 Comments Slide # 29
Indentation and Names Again

abstract class Visitor
   {
   abstract void visitTree(Node visitee);
   abstract void visitNode(Node visitee);
   }

class PreorderVisitor extends Visitor
{
   Node root;
   blah
   etc.
}

What are the issues?

Doc 15, Assignment 1 Comments Slide # 30
More Flags
public class BinaryTreeIterator implements Iterator{
   public static final int PREORDER = 1;
   public static final int INORDER = 2;
   int type;
   public boolean hasNext() {
      blah
      if (PREORDER  == type)
         do the preorder thing
      else if (INORDER == type)
         do the inorder thing
      else
         now what?
      more blah
   }
   public Object next() {
      blah
      if (PREORDER  == type)
         do the preorder thing
      else if (INORDER == type)
         do the inorder thing
      else
         now what?
      more blah
   }
}
Not how every method becomes two methods
Use two classes and each method becomes simpler

Doc 15, Assignment 1 Comments Slide # 31

Outline of Solution


Problem 1. A Binary Search Tree

Nearly everyone got this. So will not provide a solution.

Will assume three classes and one interface:


Problem 2. Iterators

Nearly everyone got this. So will not provide a solution.

Will assume two classes:



Doc 15, Assignment 1 Comments Slide # 32

Problem 3. Visitor

With traversal in Elements

class BinarySearchTree {
   public accept(Visitor visitor) {
      visitor.visitBinarySerachTree( this);
      root.accept( visitor);
   }
}
   
class BinaryNode{
   public accept(Visitor visitor) {
      visitor.visitBinaryNode( this);
      left.accept( visitor);
      right.accept( visitor);
   }
}
   
class NullNode{
   public accept(Visitor visitor) {
      visitor.visitNullNode( this);
   }
}



Doc 15, Assignment 1 Comments Slide # 33
The Visitor

class Visitor {
   integer count = 0;
   
   public visitBinarySerachTree(BinarySerachTree tree) {
   }
   
   public visitBinaryNode(BinaryNode node) {
      count++;
      reverseValue( node);
   }
   
   public visitNullNode(BinaryNode node) {
      count++;
   }
   private void reverseValue(BinaryNode node) {
      put your code here
   }
}



Doc 15, Assignment 1 Comments Slide # 34
With traversal in the Visitor

class BinarySearchTree {
   public accept(Visitor visitor) {
      visitor.visitBinarySerachTree( this);
   }
}
   
class BinaryNode{
   public accept(Visitor visitor) {
      visitor.visitBinaryNode( this);
   }
}
   
class NullNode{
   public accept(Visitor visitor) {
      visitor.visitNullNode( this);
   }
}

Performing the Traversal

BinarySearchTree studentNames;
   
Code here to populate the tree
   
Visitor reverseNames = new Visitor();
studentNames.accept( reverseNames  );


Doc 15, Assignment 1 Comments Slide # 35
The Visitor

class Visitor {
   integer count = 0;
   
   public visitBinarySerachTree(BinarySerachTree tree) {
      Node root = tree.root();
      root.accept( this );
   }
   
   public visitBinaryNode(BinaryNode node) {
      count++;
      reverseValue( node);
      Node left = node.left();
      left.accept( this );
      Node right = node.right();
      right.accept( this );
   }
   
   public visitNullNode(BinaryNode node) {
      count++;
   }
   private void reverseValue(BinaryNode node) {
      put your code here
   }
}

Doc 15, Assignment 1 Comments Slide # 36
Why accept?

Many of you did:

   public visitBinaryNode(BinaryNode node) {
      count++;
      reverseValue( node);
      if ( node.left() != null );
         visitBinaryNode( node.left() );
      if ( node.right() != null );
         visitBinaryNode( node.right() );
   }

The visitor pattern replaces case statements with polymorphism

   public visitBinaryNode(BinaryNode node) {
      count++;
      reverseValue( node);
      Node left = node.left();
      left.accept( this );
      Node right = node.right();
      right.accept( this );
   }


Doc 15, Assignment 1 Comments Slide # 37

Problem 4 Strategy


class Visitor {
   integer count = 0;
   Iterator traversal;
   public Visitor(Interator order) {
      traversal = order;
   }
   
   public visitBinarySerachTree(BinarySerachTree tree) {
      order.on( tree );
      while ( order.hasNext() ) {
         Node next = (Node) order.next();
         next.accept( this );
      }
   }
   
   public visitBinaryNode(BinaryNode node) {
      count++;
      reverseValue( node);
   }
   
   public visitNullNode(BinaryNode node) {
      count++;
   }
   private void reverseValue(BinaryNode node) { 
      blah
   }
}


Doc 15, Assignment 1 Comments Slide # 38
Performing the Traversal

BinarySearchTree studentNames;
   
Code here to populate the tree
   
Visitor reverseNames = new Visitor( new InorderIterator() );
studentNames.accept( reverseNames  );


Doc 15, Assignment 1 Comments Slide # 39
[1] Refactoring Text, pp. 250-254
[2] Refactoring Text, pp. 238-239
[3] Recall that "_" indicates an instance variable
[4] Refactoring Text, pp. 260-266

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

Previous    visitors since 10-Apr-01    Next