References | -- on slide # 1 |
Coupling | -- on slide # 3 |
...Data Coupling | -- on slide # 5 |
...Control Coupling | -- on slide # 12 |
...Global Data Coupling | -- on slide # 16 |
...Internal Data Coupling | -- on slide # 17 |
...Lexical Content Coupling | -- on slide # 18 |
Object Coupling | -- on slide # 19 |
...Interface Coupling | -- on slide # 20 |
......Object Abstraction Decoupling | -- on slide # 21 |
......Selector Decoupling | -- on slide # 23 |
......Primitive Methods | -- on slide # 24 |
......Constructors | -- on slide # 26 |
......Iterator | -- on slide # 29 |
...Inside Internal Object Coupling | -- on slide # 32 |
...Outside Internal Coupling from Underneath | -- on slide # 34 |
...Outside Internal Coupling from the Side | -- on slide # 35 |
Strength of interaction between objects in system
Cohesion
Degree to which the tasks performed by a single
module are functionally related
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
"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"
Data Coupling (weakest most desirable)
Control Coupling
Global Data Coupling
Internal Data Coupling (strongest least desirable)
Content Coupling (Unrated)
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 Receiver { public void message( MyType X ) { // code goes here X.doSomethingForMe( Object data ); // more code } }
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
Example: Sorting student records, by ID, by Name
class StudentRecord { String name; Long ID; public String getName() { return name; } // etc. } SortedList cs696 = new SortedList(); StudentRecord newStudent; //etc. cs696.add ( newStudent );
class SortedList { Object[] sortedElements = new Object[ properSize ]; public void add( StudentRecord X ) { // coded not shown Long IDa = X.getID(); Long IDb = sortedElements[ K ].getID(); if ( IDa < IDb ) // do something else // do something else } }
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 } }
Solution 3 Interfaces or "required operations"
Interface Comparable { public boolean lessThan( Object compareMe );
public boolean greaterThan( Object compareMe ); public boolean equal( Object compareMe ); } class StudentRecord implements Comparable { public boolean lessThan( Object compareMe ) { // compare student record to object compareMe } } 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 } }
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 );
typedef int (*compairFun ) ( <type>, <type> );
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 );
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();
B returns control information to A
Example: Returning error codes
Cure:
Use exceptions
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 )
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 }
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
Common Object Occurrence:
C++ Friends
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
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.
Includes module coupling already covered
Weakest form of object coupling, but has wide variation
Sub-topics
Example: List items
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 }
class LinkedListCellA { int cellItem; LinkedListCell* next; if ( cellItem == 5 ) print( "We Win" ); } class LinkedListCellB { Object cellItem; LinkedListCell* next; if ( cellItem.equals( "hi" ) ) print( "We Win" ); }
interface ListItem { public operation1();
public operation2(); }
class LinkedListCellC { ListItem cellItem; LinkedListCell* next; if ( cellItem.operation1() ) print( "We Win" ); }
class Counter { int count = 0; public void increment() { count++; } public void reset() { count = 0; } public void display() { code to display the counter }Display of Counter
"display" couples the counter object to an output object
The counter class is nearly useless do to this coupling
class Counter { int count = 0; public void increment() { count++; } public void reset() { count = 0; } public String toString() {return String.valueOf( count );} }Primitive Methods
Primitive methods are:
A composite method is any method constructed from two or more primitive methods sometimes from different objects
Constructors (not the same as class constructors)
Iterators
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 else where
class Calendar { public void getMonth( from where, or what) { } }
class Calendar { public static Calendar fromString( String date ) { } }
class Date { int year; int month; int day; }
Allows the user to visit all the nodes in a homogeneous composite object and to perform some user-supplied operation at each node
List grades = new List(); // add some grades while ( grades.nextpointer != null ) { grades = grades.nextpointer^; print( grades.examName ) }
for ( int k = 0; k < grades.length(); k++ ) print( grades.getExamNameAt( k ) );
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 );
List grades = new List(); Enumeration gradeList = grades.elements(); while ( gradeList.hasMoreElements() ) { listItem = gradeList.nextElement(); print ( listItem ); }
public interface Enumeration { /** * Returns true if the enumeration contains more elements; false * if its empty. */ boolean hasMoreElements(); /** * Returns the next element of the enumeration. Calls to this * method will enumerate successive elements. */ Object nextElement();
Coupling between state and operations of an object
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
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; };
Major Issues:
Access to inherited state
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
Unwanted Inheritance
Parent class may have operations and state not needed by subclass
Unwanted inheritance makes the subclass unnecessarily complex. This reduces
understandability and reliability.
Class A and B are not related via inheritance
Main causes:
Classes define structures
Smalltalk has classes but no type
C++ tightly couples the type hierarchy with the class hierarchy
That is a user defined type A can be a subtype of B if and only if A
is a subclass of B