Sue Evans
Press space bar for next slide
A component, at least for sake of this discussion, is a routine or module. In Python a component might be an object / class.
High-quality design leads to quality products
Abstraction and Information Hiding allow us to examine ways that components are related.
Strive to make components as independent as possible
Component coupling is the degree to which components are dependent on one another.
where Content, Common and Control Coupling are High Coupling.
Stamp Coupling is Low Coupling
and Data Coupling is, of course, very Low Coupling.
The degree of coupling decreases as we go down the list.
Python is such a strongly structured language, that it doesn't have goto or it's associated label, so content coupling isn't possible in this language. So the following code doesn't run, but you will get the idea of what content coupling is from it.
def Func1(a): print "In Func1" a += 2 goto F2A return a def Func2(): print "In Func2" F2A: print "At Func2A"
Use and Modification of a Global Variable
globalVar = 0 def Function1(a): if a > 0: globalVar += 1 a = 0 return a def Function2(): if globalVar > 0: globalVar = 42 else: globalVar = -1
Uses a flag to determine what the function will do.
This example is from a game of "Naval Battle", where the craft are indicated on the board by a letter in their name. When the user makes a guess that is a miss, an 'O' is placed on the board in that position. When the user has a hit, the character of the boat is changed from its original letter to an 'X'. When the last original letter for a craft has been hit, a message is printed indicating which craft was hit.
Here's a board in play.
linuxserver1.cs.umbc.edu[138] python naval.py 0 1 2 3 4 5 6 7 8 9 ----------------------------------------- 0 | O | | | | O | | | O | | | ----------------------------------------- 1 | | O | | | | | | | X | X | ----------------------------------------- 2 | | | | | | | | | | | ----------------------------------------- 3 | | | | | | | | | | | ----------------------------------------- 4 | | | X | X | O | | | O | | | ----------------------------------------- 5 | | | | | | | | | | | ----------------------------------------- 6 | | | | | | | | | | | ----------------------------------------- 7 | | | | | O | | | | | | ----------------------------------------- 8 | | | | | | | | | | | ----------------------------------------- 9 | | | | | | | | | | | ----------------------------------------- linuxserver1.cs.umbc.edu[139]
Here's the same game after play is done. After 30 moves, the destroyer, cruiser and battleship were sunk. The aircraft carrier was found and partially destroyed, but the sub was not found. We should show the player where the remaining craft were, as well as the shots taken.
0 1 2 3 4 5 6 7 8 9 ----------------------------------------- 0 | O | | | | O | A | | O | | | ----------------------------------------- 1 | | O | | | | A | | | X | X | ----------------------------------------- 2 | | | | O | | A | | | | O | ----------------------------------------- 3 | | | | | | X | | | | O | ----------------------------------------- 4 | O | X | X | X | O | X | | O | | O | ----------------------------------------- 5 | | | | | | | | | | O | ----------------------------------------- 6 | | O | | | | | | | | O | ----------------------------------------- 7 | S | | | | O | | X | X | X | X | ----------------------------------------- 8 | S | O | | | | | | | | | ----------------------------------------- 9 | S | | O | | | O | | | | O | ----------------------------------------- linuxserver1.cs.umbc.edu[140]
A flag called done is passed into the function. If the game is over, the flag done will be True and the board will be printed differently than if the game is not done.
A single function shouldn't have a dual purpose. We should have written two different functions, one to print the board during the game and a different one to show the player where the ships were if he lost.
def printBoard (board, rows, cols, done): print " 0 1 2 3 4 5 6 7 8 9" print " -----------------------------------------" for i in range(rows): print i, for j in range(cols): if done: print "| %c" % (board[i][j]), else: if board[i][j] == ' ' or board[i][j] == 'O' or board[i][j] == 'X': print "| %c" % (board[i][j]), else: print "| ", print "|" print " -----------------------------------------"
Stamp Coupling occurs when too much information is passed to a function.
As a rule of thumb, never pass a data structure containing many fields to a module that only needs a few.
The distinction between data and stamp coupling is not relevant in object-oriented systems.
This example is written in C, which is a procedural language. Here we are passing an entire RECTANGLE structure to each of the functions, even though the function really doesn't need to see or modify all of the members. Written this way, the function must know the names of the members and is also allowed to change any of the members. Each of these functions really should have been written to take primitive types, not the entire RECTANGLE.
typedef struct rectangle { int length; int width; int area; int perimeter; int color; double diagonal; char symbol; } RECTANGLE; RECTANGLE CalcArea (RECTANGLE r); RECTANGLE CalcPerimeter (RECTANGLE r); RECTANGLE CalcDiagonal (RECTANGLE r); int main() { RECTANGLE rect1; rect1.length = 7; rect1.width = 6; rect1.color = RED; rect1.symbol = '#'; rect1 = CalcArea (rect1); rect1 = CalcPerimeter (rect1); rect1 = CalcDiagonal (rect1); printf("For width: %d and length %d\n", rect1.width, rect1.length); printf("The area, perimeter and diagonal are\n"); printf("%d %d %f\n", rect1.area, rect1.perimeter, rect1.diagonal); return 0; } RECTANGLE CalcArea (RECTANGLE r) { r.area = r.width * r.length; return r; } RECTANGLE CalcPerimeter (RECTANGLE r) { r.perimeter = 2 * r.width + 2 * r.length; return r; } RECTANGLE CalcDiagonal (RECTANGLE r) { r.diagonal = sqrt (r.width * r.width + r.length * r.length); return r; }
This example shows a better way to write the previous program. Here we will be passing and returning only primitive data types. They are all that is really needed by the functions and now the functions are more general, too.
#define BLACK 0 #define RED 1 #define BLUE 2 typedef struct rectangle { int length; int width; int area; int perimeter; int color; double diagonal; char symbol; } RECTANGLE; int CalcArea (int width, int length); int CalcPerimeter (int width, int length); double CalcDiagonal (int width, int length); int main() { RECTANGLE rect1; rect1.length = 7; rect1.width = 6; rect1.color = RED; rect1.symbol = '#'; rect1.area = CalcArea(rect1.width, rect1.length); rect1.perimeter = CalcPerimeter(rect1.width, rect1.length); rect1.diagonal = CalcDiagonal(rect1.width, rect1.length); printf("For width: %d and length %d\n", rect1.width, rect1.length); printf("The area, perimeter and diagonal are\n"); printf("%d %d %f\n", rect1.area, rect1.perimeter, rect1.diagonal); return 0; } int CalcArea (int width, int length) { int area; area = width * length; return area; } int CalcPerimeter (int width, int length) { int perimeter; perimeter = 2 * width + 2 * length; return perimeter; } double CalcDiagonal (int width, int length) { double diagonal; diagonal = sqrt (width * width + length * length); return diagonal; }
Cohesion is the degree of interrelatedness of internal parts. All of the elements of a component are directed towards and are essential for the same task, ("A function should do one thing, and only one thing"). We should try to MAXIMIZE Cohesion.
where the degree of cohesion increases as we go down the list.
Functional cohesion should be achieved where ever possible.
Communicational and sequential cohesion represent a satisfactory
fallback level.
Logical, temporal, and procedural cohesion should be reserved for
application specific, non-reusable code.
Coincidental cohesion should not be used at all.
All of the following in one module:
Display time and date on the screen Prompt user for user-id Look up user-id in USER list If found: Prompt for password Validate password Process course enrollment request Else if not found: do error processing
Initialize two arrays Initialize several variables Seed the random number generator Print a greeting
Each in a separate module: