ModularityGoals of this LectureModule Design HeuristicsInterfacesInterface Example 1Interfaces Example 1Slide 7Slide 8Slide 9Interface Example 2Interface Example 3Slide 12EncapsulationEncapsulation Example 1Slide 15Slide 16Encapsulation Example 2Encapsulation Example 3ResourcesResources Example 1Resources Examples 2, 3SymTable AsidePassing Resource OwnershipConsistencyConsistency ExamplesMinimizationMinimization Example 1Slide 28Minimization Example 2Minimization Example 3Slide 31Reporting ErrorsReporting Errors in CReporting Errors in C (cont.)Reporting Errors Example 1Reporting Errors Examples 2, 3Establishing ContractsEstablishing Contracts in CEstablishing Contracts ExampleStrong CohesionStrong Cohesion ExamplesWeak CouplingWeak Coupling ExamplesWeak Coupling Examples (cont.)Slide 45Achieving Weak CouplingSummaryThe Rest of This Week1ModularityThe material for this lecture is drawn, in part, fromThe Practice of Programming (Kernighan & Pike) Chapter 4Professor Jennifer Rexfordhttp://www.cs.princeton.edu/~jrex2Goals of this Lecture•Help you learn how to:•Create high quality modules in C•Why?•Abstraction is a powerful (only?) technique available for understanding large, complex systems•A power programmer knows how to find the abstractions in a large program•A power programmer knows how to convey a large program’s abstractions via its modularity3Module Design Heuristics•A well-designed module:(1) Separates interface and implementation(2) Encapsulates data(3) Manages resources consistently(4) Is consistent(5) Has a minimal interface(6) Reports errors to clients(7) Establishes contracts(8) Has strong cohesion(9) Has weak coupling•Let’s consider one at a time…4Interfaces(1) A well-designed module separates interface and implementation•Why?•Hides implementation details from clients•Thus facilitating abstraction•Also allows separate compilation of each implementation•Thus facilitating partial builds5Interface Example 1•Stack: A stack whose items are strings•Data structure•Linked list•Algorithms•new: Create a new Stack object and return it•free: Free the given Stack object•push: Push the given string onto the given Stack object•top: Return the top item of the given Stack object•pop: Pop a string from the given Stack object and discard it•isEmpty: Return 1 (TRUE) iff the given Stack object is empty6Interfaces Example 1•Stack (version 1)•Stack module consists of one file (stack.c); no interface•Problem: Change stack.c => must rebuild stack.c and client•Problem: Client “sees” Stack function definitions; poor abstraction/* stack.c */struct Node { const char *item; struct Node *next;};struct Stack { struct Node *first;};struct Stack *Stack_new(void) {…}void Stack_free(struct Stack *s) {…}void Stack_push(struct Stack *s, const char *item) {…}char *Stack_top(struct Stack *s) {…}void Stack_pop(struct Stack *s) {…}int Stack_isEmpty(struct Stack *s) {…}/* client.c */#include "stack.c"/* Use the functions defined in stack.c. */7Interfaces Example 1•Stack (version 2)•Stack module consists of two files:(1) stack.h (the interface) declares functions and defines data structures/* stack.h */struct Node { const char *item; struct Node *next;};struct Stack { struct Node *first;};struct Stack *Stack_new(void);void Stack_free(struct Stack *s);void Stack_push(struct Stack *s, const char *item);char *Stack_top(struct Stack *s);void Stack_pop(struct Stack *s);int Stack_isEmpty(struct Stack *s);8Interfaces Example 1•Stack (version 2)(2) stack.c (the implementation) defines functions•#includes stack.h so•Compiler can check consistency of function declarations and definitions•Functions have access to data structures/* stack.c */#include "stack.h"struct Stack *Stack_new(void) {…}void Stack_free(struct Stack *s) {…}void Stack_push(struct Stack *s, const char *item) {…}char *Stack_top(struct Stack *s) {…}void Stack_pop(struct Stack *s) {…}int Stack_isEmpty(struct Stack *s) {…}9Interfaces Example 1•Stack (version 2)•Client #includes only the interface•Change stack.c => must rebuild stack.c, but not the client•Client does not “see” Stack function definitions; better abstraction/* client.c */#include "stack.h"/* Use the functions declared in stack.h. */10Interface Example 2•string (also recall Str from Assignment 2)/* string.h */size_t strlen(const char *s);char *strcpy(char *dest, const char *src);char *strncpy(char *dest, const char *src, size_t n);char *strcat(char *dest, const char *src);char *strncat(char *dest, const char *src, size_t n);char *strcmp(const char *s, const char *t);char *strncmp(const char *s, const char *t, size_t n);char *strstr(const char *haystack, const char *needle);…11Interface Example 3•stdio (from C90, vastly simplified)/* stdio.h */struct FILE { int cnt; /* characters left */ char *ptr; /* next character position */ char *base; /* location of buffer */ int flag; /* mode of file access */ int fd; /* file descriptor */};#define OPEN_MAX 20FILE _iob[OPEN_MAX];#define stdin (&_iob[0]);#define stdout (&_iob[1]);#define stderr (&_iob[2]);…Don’t be concernedwith details12Interface Example 3•stdio (cont.)…FILE *fopen(const char *filename, const char *mode);int fclose(FILE *f);int fflush(FILE *f);int fgetc(FILE *f);int getc(FILE *f);int getchar(void);int putc(int c, FILE *f);int putchar(int c);int fscanf(FILE *f, const char *format, …);int scanf(const char *format, …);int fprintf(FILE *f, const char *format, …);int printf(const char *format, …);…13Encapsulation(2) A well-designed module encapsulates data•An interface should hide implementation details•A module should use its functions to encapsulate its data•A module should not allow clients to manipulate the data directly•Why?•Clarity: Encourages abstraction•Security: Clients cannot corrupt object by changing its data in unintended ways•Flexibility: Allows implementation to change – even the data structure – without affecting clients14•Stack (version 1)•That’s bad•Interface reveals how Stack object is implemented (e.g., as a linked list)•Client can access/change data directly; could corrupt objectEncapsulation Example 1/* stack.h */struct Node { const char *item; struct Node *next;};struct Stack { struct Node *first;};struct Stack *Stack_new(void);void Stack_free(struct Stack *s);void
View Full Document