SDSU CS 635 Advanced Object-Oriented Design & Programming
Spring Semester, 2002
Coupling
Previous    Lecture Notes Index    Next    
© 2002, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Mar-02


References

Object Coupling and Object Cohesion, chapter 7 of Essays on Object-Oriented Software Engineering , Vol. 1, Berard, Prentice-Hall, 1993

Object-Oriented Design Heuristics, Riel, Addison-Wesley, 1996


Doc 10, Coupling Slide # 2
Quality of Objects


Decomposing systems into smaller pieces aids software development

100 functions each 100 line of code long is "better" than
One function 10,000 lines of code long


Doc 10, Coupling Slide # 3
Parnas (72) KWIC (Simple key word in context) experiment

Parnas compared two different implementations

Write down in order list of high level tasks to be done
Each high level task becomes a module (function)

List
Difficult design decisions
Design decisions that are likely to change
Each module should hide a design decision


All ways of decomposing an application are not equal


Doc 10, Coupling Slide # 4
Parnas's Criteria

Primary goal of decomposition into modules is reduction of software cost

Specific goals of module decomposition

Doc 10, Coupling Slide # 5
Metrics for quality

Coupling

Strength of interaction between objects in system


Cohesion

Degree to which the tasks performed by a single module are functionally related


Doc 10, Coupling Slide # 6

Coupling


Relationships between Objects


Type of Relations:

Type
Relation between
Uses
(Object)
Containment
(Object)
Inheritance
(Class)
Association
(Object)

Uses

Object A uses object B if A sends a message to B
Assume that A and B objects of different classes
A is the sender, B is the receiver

Containment

Class A contains class B when A has a field of type B

That is an object of type A will have an object of type B inside it


Doc 10, Coupling Slide # 7

Different Ways to Implement Uses


How does the sender access the receiver?

1. Containment

The receiver is a field in the sender

class Sender {
   Receiver here;
   
   public void method() {
      here.sendAMessage();
   }
}

2. Argument of a method

The receiver is an argument in one of the sender's methods

class Sender {
   public void method(Receiver here) {
      here.sendAMessage();
   }
}

Doc 10, Coupling Slide # 8
3. Ask someone else

The sender asks someone else to give them the receiver

class Sender {
   public void method() {
      Receiver here = someoneElse.getReceiver();
      here.sendAMessage();
   }
}

4. Creation

The sender creates the receiver
class Sender {
   public void method() {
      Receiver here = new Receiver();
      here.sendAMessage();
   }
}

5. Global

The receiver is global to the sender


Doc 10, Coupling Slide # 9

Heuristics for the Uses Relationship


4.1 Minimize the number of classes with another class collaborates





Doc 10, Coupling Slide # 10
4.2 Minimize the number of message sends between a class and its collaborator

4.3 Minimize the number of different messages a class sends to another class.

4.4 Minimize the product of the number of methods in a class and the number of different messages they send.

Which is more complex?





Doc 10, Coupling Slide # 11

Decomposable system

One or more of the components of a system have no interactions or other interrelationships with any of the other components at the same level of abstraction within the system


A nearly decomposable system

Every component of the system has a direct or indirect interaction or other interrelationship with every other component at the same level of abstraction within the same system


Design Goal

The interaction or other interrelationship between any two components at the same level of abstraction within the system be as weak as possible


Doc 10, Coupling Slide # 12
Coupling

Measure of the interdependence among modules

"Unnecessary object coupling needlessly decreases the reusability of the coupled objects "

"Unnecessary object coupling also increases the chances of system corruption when changes are made to one or more of the coupled objects"


Doc 10, Coupling Slide # 13


Types of Modular CouplingIn order of desirability

Data Coupling (weakest – most desirable)

Control Coupling

Global Data Coupling

Internal Data Coupling (strongest – least desirable)

Content Coupling (Unrated)

Doc 10, Coupling Slide # 14
Modular Coupling

Data Coupling



Output from one module is the input to another

Using parameter lists to pass items between routines

Common Object Occurrence:

Object A passes object X to object B
Object X and B are coupled
A change to X's interface may require a change to B

Example

class ObjectBClass{
   public void message( ObjectXClass X ){
      // code goes here
      X.doSomethingForMe( Object data );
      // more code
   }
}

Doc 10, Coupling Slide # 15
Modular CouplingData Coupling

Major Problem
Object A passes object X to object B
X is a compound object
Object B must extract component object Y out of X
B, X, internal representation of X, and Y are coupled



Doc 10, Coupling Slide # 16
Example: Sorting student records, by ID, by Name



class StudentRecord {
   Name lastName;
   Name firstName;
   long ID;
   
   public Name getLastName() { return lastName; }
   // etc.
}
SortedList cs535 = new SortedList();
StudentRecord newStudent;
//etc.
cs535.add ( newStudent );


Doc 10, Coupling Slide # 17
Solution 1 Bad News



class SortedList
   {
   Object[] sortedElements = new Object[ properSize ];
   public void add( StudentRecord X )
      {
      // coded not shown
      Name a = X.getLastName();
      Name b = sortedElements[ K ].getLastName();
      if ( a.lessThan( b ) )
         // do something
      else
         // do something else
      }
   }
SortList>>add: aStudentRecord
   Blah
   a := aStudentRecord lastName.
   b := sortedElements at: k.
   blah

Doc 10, Coupling Slide # 18
Solution 2  Send message to object to compare self to another StudentRecord Object


class SortedList{
   Object[] sortedElements = new Object[ properSize ];
   public void add( StudentRecord X ) {
      // coded not shown
      if ( X.lessthan( sortedElements[ K ] ) )
         // do something
      else
         // do something else
   }
}
class StudentRecord{
   private Name lastName;
   private long ID;
   public boolean lessThan( Object compareMe ) {
      return lastName.lessThan( compareMe.lastName );
   }
   etc.
}
SortList>>add: aStudentRecord
   Blah
   aStudentRecord <  sortedElements last
      ifTrue: [ more blah ]
      ifFalse: [ blah blah ]
   blah

Doc 10, Coupling Slide # 19
Solution 3  Program to an Interface or "required operations"

interface Comparable {
   public boolean lessThan( Object compareMe ); 
   public boolean greaterThan( Object compareMe ); 
   public boolean equal( Object compareMe ); 
}
class StudentRecord implements Comparable {
   private Name lastName;
   private long ID;
   public boolean lessThan( Object compareMe ) {
      return lastName.lessThan( ((Name)compareMe).lastName );
   }
}
class SortedList {
   Object[] sortedElements = new Object[ properSize ];
   public void add( Comparable X ) {
      // coded not shown
      if ( X.lessthan( sortedElements[ K ] )
         // do something
      else
         // do something else
      }
   }
    
SortList>>add: anObject
   anObject <  sortedElements last
      ifTrue: [ more blah ]
      ifFalse: [ blah blah ]
   blah

Doc 10, Coupling Slide # 20
Solution 4 Strategy Pattern & Blocks

| sortedStudents |
   
sortedStudents := SortedCollection sortBlock: 
         [:x :y | x lastName < y lastName].
   
blah
   
sortedStudents 
   add: roger;
   add: pete;
   add: sam.
 
sortedStudents sortBlock: [:x :y | x grade < y grade ]

Doc 10, Coupling Slide # 21
Solution 4 Strategy Pattern & Function Pointers
Code is neither legal C/C++ nor Java. The idea is to pass in a function pointer to the SortList object, which it uses to compare the objects in the list.
typedef int (*compareFun ) ( StudentRecord, StudentRecord );
class SortedList {
   StudentRecord[] sortedElements = 
         new StudentRecord[ properSize ];
    int (*compare ) ( StudentRecord, StudentRecord );
   public setCompare( compairFun newCompare )
      { compare = newCompare; }
   public void add( StudentRecord X ) {
      // coded not shown
      if ( compare( X,  sortedElements[ K ] ) )
      // code not shown
   }
}
 
int compareID( StudentRecord a, StudentRecord b )
   { // code not shown }
 
int compareName( StudentRecord a, StudentRecord b )
   { // code not shown }
SortedList myList = new SortedList();
myList.setCompair( compareID );

Doc 10, Coupling Slide # 22
Functor PatternFunctions as Objects

Functors are functions that behave like objects

They serve the role of a function, but can be created, passed as parameters, and manipulated like objects

A functor is a class with a single member function




Doc 10, Coupling Slide # 23
Function Pointers in JavaComparator in Java 2 (JDK 1.2)


Methods in Comparator Interface
int compare(Object o1, Object o2)
Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second
boolean equals(Object obj)
Indicates whether some other object is "equal to" this Comparator.

The implementer must ensure that:

sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y

compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)

((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

x.equals(y) || (x==null && y==null) implies that compare(x, y)==0.

compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

Doc 10, Coupling Slide # 24
Comparator Example

import java.util. Comparator;
class Student  {
   String name;
   int id;
   
   public Student( String newName, int id ) {
      name = newName;
      this.id = id;
      }
   
   public String toString() {
      return name + ":" + id;
      }
   }
final class StudentNameComparator implements Comparator {
   
   public int compare( Object leftOp, Object rightOp ) {
      String leftName = ((Student) leftOp).name;
      String rightName = ((Student) rightOp).name;
      return leftName.compareTo( rightName );
   }
   
   public boolean equals( Object comparator ) {
      return comparator instanceof StudentNameComparator;
   }
}

Doc 10, Coupling Slide # 25
//Comparator Example Continued

final class StudentIdComparator implements Comparator {
   static final int LESS_THAN = -1;
   static final int GREATER_THAN = 1;
   static final int EQUAL = 0;
   
   public int compare( Object leftOp, Object rightOp ) {
      long leftId = ((Student) leftOp).id;
      long rightId = ((Student) rightOp).id;
      if ( leftId < rightId )   
         return LESS_THAN;
      else if ( leftId > rightId )
         return GREATER_THAN;
      else
         return EQUAL;
   }
   
   public boolean equals( Object comparator ) {
      return comparator instanceof StudentIdComparator;
   }
}

Doc 10, Coupling Slide # 26
//Comparator Example Continued
import java.util.*;
public class Test  {
   public static void main(String args[])  {
      Student[] cs596 = { new Student( "Li", 1 ), new Student( "Swen", 2 ), 
                                 new Student( "Chan", 3 ) };
      //Sort the array
      Arrays.sort( cs596, new StudentNameComparator() );
      for ( int k = 0; k < cs596.length; k++ )
         System.out.print( cs596[k].toString() + ", " );
      System.out.println( );
      
      List cs596List = new ArrayList( );
      cs596List.add( new Student( "Li", 1 ) );
      cs596List.add( new Student( "Swen", 2 ) );
      cs596List.add( new Student( "Chan", 3 ) );
      System.out.println( "Unsorted list " + cs596List );
      //Sort the list
      Collections.sort( cs596List,  new StudentNameComparator() );
      System.out.println( "Sorted list " + cs596List );
      //TreeSets are aways sorted
      TreeSet cs596Set = new TreeSet(  new StudentNameComparator() );
      cs596Set.add( new Student( "Li", 1 ) );
      cs596Set.add( new Student( "Swen", 2 ) );
      cs596Set.add( new Student( "Chan", 3 ) );
      System.out.println( "Sorted Set " + cs596Set );
   }
}

Doc 10, Coupling Slide # 27
//Comparator Example ContinuedOutput
Chan:3, Li:1, Swen:2, 
Unsorted list [Li:1, Swen:2, Chan:3]
Sorted list [Chan:3, Li:1, Swen:2]
Sorted Set [Chan:3, Li:1, Swen:2]

Doc 10, Coupling Slide # 28
Sorting With Different Keys
import java.util.*;
public class MultipleSorts {
   public static void main(String args[]) {
      List cs596List = new ArrayList( );
      cs596List.add( new Student( "Li", 1 ) );
      cs596List.add( new Student( "Swen", 2 ) );
      cs596List.add( new Student( "Chan", 3 ) );
      
      Collections.sort( cs596List,  new StudentNameComparator() );
      System.out.println( "Name Sorted list " + cs596List );
      Collections.sort( cs596List,  new StudentIdComparator() );
      System.out.println( "Id Sorted list " + cs596List );
      TreeSet cs596Set = new TreeSet( new StudentNameComparator());
      cs596Set.addAll( cs596List );
      System.out.println( "Name Sorted Set " + cs596Set );
      TreeSet cs596IdSet = new TreeSet( new StudentIdComparator() );
      cs596IdSet.addAll( cs596List );
      System.out.println( "Id Sorted Set " + cs596IdSet );
   }
}
Output
Name Sorted list [Chan:1, Li:2, Swen:1]
Id Sorted list [Chan:1, Swen:1, Li:2]
Name Sorted Set [Chan:1, Li:2, Swen:1]
Id Sorted Set [Chan:1, Li:2]
 

Doc 10, Coupling Slide # 29
Modular Coupling

Control Coupling


Passing control flags between modules so that one module controls the sequencing of the processing steps in another module

Common Object Occurrences:

A sends a message to B
B uses a parameter of the message to decide what to do

class Lamp {
   public static final ON = 0;
   public void setLamp( int setting ) {
      if ( setting == ON )
         //turn light on
      else if ( setting == 1 )
         // turn light off
      else if ( setting == 2 )
         // blink
   }
}
Lamp reading = new Lamp();
reading.setLamp( Lamp.ON );
reading.setLamp)( 2 );

Doc 10, Coupling Slide # 30
Cure:
Decompose the operation into multiple primitive operations

class Lamp {
   public void on() {//turn light on }
   public void off() {//turn light off }
   public void blink() {//blink }
}
Lamp reading = new Lamp();
reading.on();
reading.blink();


Doc 10, Coupling Slide # 31
Is this Control Coupling?


BankAccount>>withdrawal: aFloat
   balance := balance – aFloat.


What about?

BankAccount>>withdrawal: aFloat
   balance < aFloat
      ifTrue: [ self bounceThisCheck ]
      ifFalse: [balance := balance – aFloat]


Doc 10, Coupling Slide # 32
Control Coupling

Common Object Occurrences:

A sends a message to B
B returns control information to A

Example: Returning error codes

class Test {
   public int printFile( File toPrint ) {
      if ( toPrint is corrupted )
         return CORRUPTFLAG;
      blah blah blah
   }
}
Test when = new Test();
int result =  when.printFile( popQuiz );
if ( result == CORRUPTFLAG )
   blah
else if ( result == -243 )

Doc 10, Coupling Slide # 33
Cure: Use exceptions


class Test  {
   public int printFile( File toPrint ) throws PrintExeception {
      if ( toPrint is corrupted )
         throws new PrintExeception();
      blah blah blah
   }
}
try {
   Test when = new Test();
   when.printFile( popQuiz );
}
catch ( PrintException printError ) {
   do something
}

Doc 10, Coupling Slide # 34
Modular Coupling

Global Data Coupling


Two or more modules share the same global data structures

Common Object Occurrence :

A method in one object makes a specific reference to a specific external object

A method in one object makes a specific reference to a specific external object, and to one or more specific methods in the interface to that external object

A component of an object-oriented system has a public interface which consists of items whose values remain constant throughout execution, and whose underlying structures/implementations are hidden

A component of an object-oriented system has a public interface which consists of items whose values remain constant throughout execution, and whose underlying structures/implementations are not hidden

A component of an object-oriented system has a public interface which consists of items whose values do not remain constant throughout execution, and whose underlying structures/implementations are hidden

A component of an object-oriented system has a public interface which consists of items whose values do not remain constant throughout execution, and whose underlying structures/implementations are not hidden

Doc 10, Coupling Slide # 35

Internal Data Coupling


One module directly modifies local data of another module

Common Object Occurrence:

C++ Friends



Doc 10, Coupling Slide # 36
Modular Coupling

Lexical Content Coupling


Some or all of the contents of one module are included in the contents of another

Common Object Occurrence :

C/C++ header files


Decrease coupling by:

Restrict what goes in header file
C++ header files should contain only class interface specifications


Doc 10, Coupling Slide # 37

Object Coupling



Coupling measures the strength of the physical relationships among the items that comprise an object

Cohesion measures the logical relationship among the items that comprise an object

Interface coupling is the coupling between an object and all objects external to it. Interface coupling is the most desirable form of object coupling. Internal coupling is coupling among the items that make up an object.

Doc 10, Coupling Slide # 38
Object Coupling

Interface Coupling


Interface coupling occurs when one object refers to another specific object, and the original object makes direct references to one or more items in the specific object's public interface

Includes module coupling already covered

Weakest form of object coupling, but has wide variation

Sub-topics
Object abstraction decoupling
Selector decoupling
Constructor decoupling
Iterator decoupling


Doc 10, Coupling Slide # 39

Object Abstraction Decoupling


Assumptions that one object makes about a category of other objects are isolated and used as parameters to instantiate the original object.

Example: List items


C++ Example
class LinkedListCell {
   int cellItem;
   LinkedListCell* next;
   // code can now use fact that cellItem is an int
   if ( cellItem == 5 ) print( "We Win" );
}
template <class type>
class LinkedListCell#2 {
   type cellItem;
   LinkedListCell* next;
   // code does not know the type, it is just a cell item,
   // it becomes an abstraction
}

Doc 10, Coupling Slide # 40
Java Example



class LinkedListCellA {
   int cellItem;      
   LinkedListCell next;
   if ( cellItem == 5 ) print( "We Win" );
}
class LinkedListCellB {
   Object  cellItem;
   LinkedListCell next;
   if ( cellItem.operation1() ) print( "We Win" );
}

Doc 10, Coupling Slide # 41

Selector Decoupling


Example: Counter object

class Counter{
   int count = 0;
   public void increment()    {  count++; }
   public void reset()    { count = 0; }
   public void display()    {
      code to display the counter in a slider bar
}

Display of Counter



"display" couples the counter object to a particular output type

The counter class can not be used in other setting due to this coupling

Better Counter Class
class Counter{
   int count = 0;
   public void increment()    {  count++; }
   public void reset()    { count = 0; }
   public int count()      {return count;}
   public String toString() {return String.valueOf( count );}
   }

Doc 10, Coupling Slide # 42

Primitive Methods


A primitive method is any method that cannot be implemented simply, efficiently, and reliably without knowledge of the underlying implementation of the object


Primitive methods are:

Functionally cohesive, they perform a single specific function
Small, seldom exceed five "lines of code"


A composite method is any method constructed from two or more primitive methods – sometimes from different objects

Types of Primitive Operations

Selectors (get operations)
Constructors (not the same as class constructors)
Iterators


Doc 10, Coupling Slide # 43

Selectors


Selectors are encapsulated operations which return state information about their encapsulated object and do not alter the state of their encapsulated object

Replacing

   public void display()    {
      code to display the counter
   }

with

   public String toString() {return String.valueOf( count );}

is an example of Selector decoupling.

By replacing a composite method (display) with a primitive method the Counter class is decoupled from the display device

This makes the Counter class far more useful

It also moves the responsibility of displaying the counter elsewhere

Doc 10, Coupling Slide # 44

Constructors


Operations that construct a new, or altered version of an object



class Calendar {
   public void getMonth( from where, or what) { blah }
}

class Calendar {
   public static Calendar fromString( String date ) { blah}
}

Doc 10, Coupling Slide # 45
Primitive Objects

Primitive objects are objects that are both:


This can include standard libraries and standard environments


That is any object that is known in any part of any application created using the implementation language

Primitive objects don't count in coupling with other objects

"An object that refers to itself and to primitive objects is considered for all intents and purposes, totally decoupled from other objects "


Doc 10, Coupling Slide # 46
Composite Object

Object conceptually composed of two or more objects



Heterogeneous Composite Object

Object conceptually composed from objects which are not all conceptually the same


class Date{
   int year;
   int month;
   int day;
}

Homogeneous Composite Object

Object conceptually composed from objects which are all conceptually the same

list of names - each item is a member of the same general category of object – a name


Doc 10, Coupling Slide # 47
Iterator

Allows the user to visit all the nodes in a homogeneous composite object and to perform some user-supplied operation at each node

Both Java and C++ support iterators


Doc 10, Coupling Slide # 48
Passive Iterator



class List {
   Object[] listElements = new Object[ size ];
   public void do( Function userOperation ) {
      for ( int k = 0; k < listElements.length(); k++ )
         userOperation( listElements[ k ] );
   }
}

In Main

   List grades = new List();
   aFunction = ( item ){ print( item ) };
   grades.do ( aFunction );


Doc 10, Coupling Slide # 49
Active Iterator


List grades = new List();
Iterator gradeList = grades.iterator();
while ( gradeList.hasNext() ){
   listItem = gradeList.next();
   print ( listItem );
   }

Java Enumeration/Iterator

Methods
Enumeration
Iterator
ListIterator
hasMoreElements()
hasNext()
hasNext()
nextElement()
next()
next()

remove()
remove()


nextIndex()


hasPrevious()


previous()


previousIndex()


add()


set()

Iterators go through elements of a collection.

Iterator and ListIterator are fail-fast

If the underlying collection is changed (elements added or removed) by means other than the iterator, then the next time the iterator is accessed it will throw a java.util.ConcurrentModificationException

Doc 10, Coupling Slide # 50
Iterators and Coupling



Array
int[] list 
for (int k = 0; k < list.length; k ++ )
   System.out.println( list[k] );
Vector
Vector list 
for (int k =0; k < list.size(); k++ )
   Sytem.out.println( list.elementAt( k ) );
Binary Search Tree
BinarySeachTree list
Node current = list.root();
Stack previous = new Stack();
Previous.push( current );
while (current != null )
   {
   a lot of code here
   }

Doc 10, Coupling Slide # 51
Java Collection Classes



There are synchronized, unsynchronized, modifiable unmodifiable versions of each collection/map

One can set the modifiable and synchronized property separately


What about Arrays?



One can convert an array of objects to a list

String[] example = new String[10];
List listBackedByArray = Arrays.asList( example );

Changes to the array(list) are reflected in the list(array)

Doc 10, Coupling Slide # 52
Less Coupling with Iterators

Collection list;
Iterator elements = list.iterator();
while (elements.hasNext() ) {
   System.out.println( elements.next() );
}

In this code list could be any type of collection, so is more flexible. It is not coupled to a particular type of collection.


Doc 10, Coupling Slide # 53

Inside Internal Object Coupling


Coupling between state and operations of an object

The big issue: Accessing state

Changing the structure of the state of an object requires changing all operations that access the state including operations in subclasses

Solution: Access state via access operations

C++ implementation
Provide private functions to access and change each data member

Simple Cases:

One function to access the value of the date member
One function to change the value of the data member
Only these two functions can access the data member


Doc 10, Coupling Slide # 54
Accessing StateC++ Example

class Counter{
public:
   void increment(void);
private:
   int  value;
   
   void  setValue(int newValue);
   int  getValue(void);
};
void Counter::increment(void)    //Increase counter by one {
   setValue(getValue() + 1);
};
void Counter::setValue(int newValue) {
   value = newValue;
};
int Counter::getValue {
   return value;
};

Doc 10, Coupling Slide # 55

Outside Internal Coupling from Underneath


Coupling between a class and subclass involving private state and private operations


Major Issues:


Direct access to inherited state
See inside internal object coupling
Access via operations
Inherited operations may not be sufficient set of operations to access state for subclass


Parent class may have operations and state not needed by subclass
Unwanted inheritance makes the subclass unnecessarily complex. This reduces understandability and reliability.


Doc 10, Coupling Slide # 56

Outside Internal Coupling from the Side


Class A accesses private state or private operations of class B

Class A and B are not related via inheritance


Main causes:

Using nonobject-oriented languages
Special language "features"
C++ friends


Donald Knuth

"First create a solution using sound software engineering techniques, then if needed, introduce small violations of good software engineering principles for efficiency's sake."


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

Previous    visitors since 21-Mar-02    Next