object and class creational design patterns

31
1 Object and Class Object and Class Creational Creational Design Patterns Design Patterns The practicality of The practicality of modules modules CS 236700: Software Design

Upload: alize

Post on 12-Jan-2016

43 views

Category:

Documents


0 download

DESCRIPTION

Object and Class Creational Design Patterns. The practicality of modules. CS 236700: Software Design. Usage (1/2). Let’s consider the following directory…. …Then, we can use imgdir.exe as follows:. C:>imgdir.exe a.gif b.jpg c.bmp a.gif,GIF,273,310 b.jpg,JPG,128,82 c.bmp,BMP,128,82. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Object and Class Creational Design Patterns

1

Object and ClassObject and ClassCreationalCreational

Design PatternsDesign Patterns

The practicality of modulesThe practicality of modules

CS 236700: Software Design

Page 2: Object and Class Creational Design Patterns

2

Usage (1/2)Usage (1/2)Let’s consider the following directory…

…Then, we can use imgdir.exe as follows:

C:>imgdir.exe a.gif b.jpg c.bmpa.gif,GIF,273,310b.jpg,JPG,128,82c.bmp,BMP,128,82

C:>imgdir.exe a.gif b.jpg c.bmpa.gif,GIF,273,310b.jpg,JPG,128,82c.bmp,BMP,128,82

Page 3: Object and Class Creational Design Patterns

3

Usage (2/2)Usage (2/2) Command line options:

C:\temp>imgdir.exeimgdir [-S <sep>] [-f <fields>] [-V] file1 file2 ... -s field separator enclosed in quotes

-f fields to display: N-name T-type, W-width, H-height example "NTWH“

-v verbose mode: non image files are listed as well

C:\temp>imgdir.exeimgdir [-S <sep>] [-f <fields>] [-V] file1 file2 ... -s field separator enclosed in quotes

-f fields to display: N-name T-type, W-width, H-height example "NTWH“

-v verbose mode: non image files are listed as well

Page 4: Object and Class Creational Design Patterns

4

Current state: Imgdir is written in C.

Original source code - 465 lines. Some bugs were fixed so we can have a clean start Code quality is poor Code style is poor

Our mission:

The missionThe mission

Rewrite imgdir.c in a modular wayRewrite imgdir.c in a modular way

We CANNOT use classes We CAN use other C++ features: namespaces, overloading,… No textbook solution

Page 5: Object and Class Creational Design Patterns

5

Source code overview (1/3)Source code overview (1/3)

/* Command line codes: */#define FIELDOPTION 1 /* for –f <fields> */#define SEPOPTION 2 /* for –s <sep> */#define VERBOSEOPTION 3 /* for –v */#define NOTOPTION 0 /* indicates a file name */

typedef struct { char *sep; /* seperator string for fields */ char *fields; /* fields to display: nthw */ int fieldlen; /* == strlen(fields) short verbose; /* 1 – Verbose mode is ON */} DISPLAYOPTIONS;

/* Command line codes: */#define FIELDOPTION 1 /* for –f <fields> */#define SEPOPTION 2 /* for –s <sep> */#define VERBOSEOPTION 3 /* for –v */#define NOTOPTION 0 /* indicates a file name */

typedef struct { char *sep; /* seperator string for fields */ char *fields; /* fields to display: nthw */ int fieldlen; /* == strlen(fields) short verbose; /* 1 – Verbose mode is ON */} DISPLAYOPTIONS;

Page 6: Object and Class Creational Design Patterns

6

Source code overview (2/3)Source code overview (2/3)

#define NOTYPE 0 #define JPEGTYPE 1#define GIFTYPE 2#define BMPTYPE 3

typedef struct { int imgtype; /* NOTYPE, JPEGTYPE, etc..*/ char *imgtypename; /* “BMP”, “GIF”, or “JPG” */ char *filename; long width; /* width of image in pixels */ long height; /* height of image in pixels */} IMAGEINFO;

#define NOTYPE 0 #define JPEGTYPE 1#define GIFTYPE 2#define BMPTYPE 3

typedef struct { int imgtype; /* NOTYPE, JPEGTYPE, etc..*/ char *imgtypename; /* “BMP”, “GIF”, or “JPG” */ char *filename; long width; /* width of image in pixels */ long height; /* height of image in pixels */} IMAGEINFO;

Page 7: Object and Class Creational Design Patterns

7

Source code overview (3/3)Source code overview (3/3)

void swapShort(short, short *); void swapLong(long, long *);int ffindMarker(FILE *, int, int,long);int setOption(int,char **, int, DISPLAYOPTIONS *); int getOptionCode(char *); void imageType(char *, IMAGEINFO *);void imageSize(IMAGEINFO *);

int isjpg(char *); /* 1 – true, 0 - false */int isgif(char *);int isbmp(char *);void jpegSize(char *, long *,long *); void gifSize(char *, long *,long *);void bmpSize(char *, long *,long *);

void dspEntry(DISPLAYOPTIONS*, IMAGEINFO*);void dspUsage();

void main(int,char **);

void swapShort(short, short *); void swapLong(long, long *);int ffindMarker(FILE *, int, int,long);int setOption(int,char **, int, DISPLAYOPTIONS *); int getOptionCode(char *); void imageType(char *, IMAGEINFO *);void imageSize(IMAGEINFO *);

int isjpg(char *); /* 1 – true, 0 - false */int isgif(char *);int isbmp(char *);void jpegSize(char *, long *,long *); void gifSize(char *, long *,long *);void bmpSize(char *, long *,long *);

void dspEntry(DISPLAYOPTIONS*, IMAGEINFO*);void dspUsage();

void main(int,char **);

Page 8: Object and Class Creational Design Patterns

8

Why do we want to rewrite the source code ? Suppose, we want to change the value of NOTOPTION to -1:

#define NOTOPTION -1 //previously 0The problem:

The mission (continued)The mission (continued)

void main(int argc, char *argv[]){ // .. for(i = 1; i < argc; ++i) { int t; if(t = getOptionCode(argv[i]) { // Do something } else break; } // .. Rest of main()

void main(int argc, char *argv[]){ // .. for(i = 1; i < argc; ++i) { int t; if(t = getOptionCode(argv[i]) { // Do something } else break; } // .. Rest of main()

NOTOPTION is now -1 => t is never 0

Page 9: Object and Class Creational Design Patterns

9

In imgdir.c a small change can create program-wide bugs Poor continuity

The program has a flat structure => we must check all 15 functions No separation => every function can be effected

Relevant terms: dependency, coupling, cohesion, continuity

So, let’s make this thing modular…

AnalysisAnalysis

Page 10: Object and Class Creational Design Patterns

10

We will use namespaces as modules Each function will “move” into an appropriate module The initial list of modules:

<main>:

main() <isimage>:

imageType(), isjpg(), isbmp(), isgif() <sizeofimage>:

imageSize(), jpegSize(), bmpSize(), gifSize() <utils>:

ffindMarker(), swapShort(), swapLong() <commandline>:

getOptionCode(), setOption() <display>:

dspEntry(), dspUsage()

Module breakdown – stage 1Module breakdown – stage 1

Imgdir.c-stage1

Page 11: Object and Class Creational Design Patterns

11

Shows the “usage” relation between modules Built by checking function calls between modules

Dependency graphDependency graph

<Main>

<Commandline> <sizeofimage>

<utils>

<isimage><display>

Activities of main(): scans the command line builds display the option For each image:

Check image type Find size Display the data

Number of edges

= 6

A little problem:How does <display> know the details of the current image (width, height, type…) ??

Imgdir.c-stage1

Page 12: Object and Class Creational Design Patterns

12

The image details are passed via an IMAGEINFO struct. A function call is not the only source of dependency

Other C elements can also yield a dependency: typedef, struct, enum

=> Let’s place more elements in our modules IMAGEINFO is placed inside <isimage> DISPLAYOPTIONS is placed inside <display>

Dependency graphDependency graph

<main>

<Commandline> <sizeofimage>

<utils>

<isimage><display>

Number of edges

= 9

Imgdir.c-stage2

Page 13: Object and Class Creational Design Patterns

13

After adding IMAGEINFO and DISPLAYOPTIONS <main>:

main() <isimage>:

imageType(), isjpg(), isbmp(), isgif(), IMAGEINFO <sizeofimage>:

imageSize(), jpegSize(), bmpSize(), gifSize() <utils>:

ffindMarker(), swapShort(), swapLong() <commandline>:

getOptionCode(), setOption() <display>:

dspEntry(), dspUsage(), DISPLAYOPTIONS

Module breakdown – stage 2Module breakdown – stage 2

Imgdir.c-stage2

Page 14: Object and Class Creational Design Patterns

14

Considering <isimage>, <sizeofimage>, <utils>: <utils> is a shared module <utils> is an implementation detail There are only three elements used by <main>, <display>:

IMAGEINFO, imageType(), imageSize() => Define a new module: <image>

A module which contains sub-modules:• <utils>, <sizeofimage>, <isimage>

We can simulate public/private access level

Coupling reduction (1/4)Coupling reduction (1/4)

<main>

<commandline> <sizeofimage>

<utils>

<isimage><display>

Number of edges

= 5

<main>

<commandline>

<image>(<isimage>,<sizeofimage>, <utils>)

<display>

Page 15: Object and Class Creational Design Patterns

15

A new module was created: <image> <main>:

main() <image>

imageType(), imageSize(), IMAGEINFO <isimage>:

isjpg(), isbmp(), isgif(), <sizeofimage>:

jpegSize(), bmpSize(), gifSize() <utils>:

ffindMarker(), swapShort(), swapLong() <commandline>:

getOptionCode(), setOption() <display>:

dspEntry(), dspUsage(), DISPLAYOPTIONS

Coupling reduction (2/4)Coupling reduction (2/4)

Page 16: Object and Class Creational Design Patterns

16

Considering <main>,<display>,<commandline>: <main> is coupled with 3 other modules – Too much The reason for <main>’s coupling with <commandline>:

for(i = 1; i < argc; ++i) {

if(t = getOption(..)) setOption(..)

else break; }

Our next step: Move the loop into <display>

• A new function in <display>: buildOptions() Place <commandline> inside <display>

Coupling reduction (3/4)Coupling reduction (3/4)

Imgdir.c-stage3

Number of edges

= 3

<display>(<commandline>)

<main>

<image>(<isimage>,<sizeofimage>, <utils>)

<display>

<main>

<image>(<isimage>,<sizeofimage>, <utils>)

<commandline>

Page 17: Object and Class Creational Design Patterns

17

<commandline> moved into <display>: <main>:

main() <image>

imageType(), imageSize(), IMAGEINFO <isimage>:

isjpg(), isbmp(), isgif(), <sizeofimage>:

jpegSize(), bmpSize(), gifSize() <utils>:

ffindMarker(), swapShort(), swapLong() <display>:

dspEntry(), dspUsage(), DISPLAYOPTIONS, buildOptions() <commandline>:

getOptionCode(), setOption()

Coupling reduction (4/4)Coupling reduction (4/4)

Imgdir.c-stage3

Page 18: Object and Class Creational Design Patterns

18

What else? use enum instead of #define

Obeys scope rules => Can be hidden inside a module

Rewrite using classes ?!

Additional stepsAdditional steps

Page 19: Object and Class Creational Design Patterns

19

Friendly suggestion: coupling reduction at the system’s upper-level is usually the best place to start.

We used number of edges as a “modularity meter” There are other important factors, such as:

circles number of modules number of functions per module

The “algorithm” Work on the “Most-coupled” modules

In our case: <main> Shared modules => make them private sub-modules

In our case: <utils> was moved into the new module <image> Creating new modules can decrease coupling

<image> Don’t forget the non-function elements: typedefs, structs, enums,…

Summary: Coupling reductionSummary: Coupling reduction

Page 20: Object and Class Creational Design Patterns

20

Imgdir.c - Source code Imgdir.c - Source code

Page 21: Object and Class Creational Design Patterns

21

ffindMarker()ffindMarker()

int ffindMarker(FILE *infile, int c1, int c2,long mxbytes){ int c,done,rval,state; long bytecount;

rval = 0; state = 0; done = 0; bytecount = 0; while (!done) { if ((bytecount == mxbytes) && (mxbytes != 0)) { done = 1; } else { c = fgetc(infile); if (mxbytes != 0) bytecount++; }

int ffindMarker(FILE *infile, int c1, int c2,long mxbytes){ int c,done,rval,state; long bytecount;

rval = 0; state = 0; done = 0; bytecount = 0; while (!done) { if ((bytecount == mxbytes) && (mxbytes != 0)) { done = 1; } else { c = fgetc(infile); if (mxbytes != 0) bytecount++; }

switch (state) { case 0: if ( c == c1) state = 1; else if ( c == EOF) done = 1; break; case 1: if ( c == c2) { done = 1; rval = 1; } else if (c == EOF) done = 1; else { fseek(infile, -1, SEEK_CUR); state = 0; } break; } } return rval;}

switch (state) { case 0: if ( c == c1) state = 1; else if ( c == EOF) done = 1; break; case 1: if ( c == c2) { done = 1; rval = 1; } else if (c == EOF) done = 1; else { fseek(infile, -1, SEEK_CUR); state = 0; } break; } } return rval;}

Page 22: Object and Class Creational Design Patterns

22

setOption()setOption()

int setOption(int opt, char **argv, int index, DISPLAYOPTIONS *dsp){ switch (opt) { case FIELDOPTION : dsp->fields = argv[++index]; dsp->fieldlen = dsp->fields; break; case SEPOPTION : dsp->sep = argv[++index]; break; case VERBOSEOPTION : dsp->verbose = 1; break; } return index; /* index of last argv entry that was read */}

int setOption(int opt, char **argv, int index, DISPLAYOPTIONS *dsp){ switch (opt) { case FIELDOPTION : dsp->fields = argv[++index]; dsp->fieldlen = dsp->fields; break; case SEPOPTION : dsp->sep = argv[++index]; break; case VERBOSEOPTION : dsp->verbose = 1; break; } return index; /* index of last argv entry that was read */}

Page 23: Object and Class Creational Design Patterns

23

swapShort()swapShort()

void swapShort(short i, short *t){ char *pi; char *pt; pi = (char *)&i; pt = (char *)t; pt[0] = pi[1]; pt[1] = pi[0];}

void swapShort(short i, short *t){ char *pi; char *pt; pi = (char *)&i; pt = (char *)t; pt[0] = pi[1]; pt[1] = pi[0];}

Page 24: Object and Class Creational Design Patterns

24

getOptionCode()getOptionCode()

int getOptionCode(char *opt){ int rval;

if(strcmp(opt,"-f")== 0) rval = FIELDOPTION; else if(strcmp(opt,"-s")== 0) rval = SEPOPTION; else if(strcmp(opt,"-v") == 0) rval = VERBOSEOPTION; else rval = NOTOPTION;

return rval;}

int getOptionCode(char *opt){ int rval;

if(strcmp(opt,"-f")== 0) rval = FIELDOPTION; else if(strcmp(opt,"-s")== 0) rval = SEPOPTION; else if(strcmp(opt,"-v") == 0) rval = VERBOSEOPTION; else rval = NOTOPTION;

return rval;}

Page 25: Object and Class Creational Design Patterns

25

isJpg()isJpg()

int isjpg(char *fname){ int rval; FILE *infile; rval = 0; infile = fopen(fname,"rb");

/* look for jpeg markers in first two bytes */ if(ffindMarker(infile,0xff,0xd8,2L)) rval = 1;

/* check last two bytes for end marker */ fseek(infile, -2, SEEK_END); rval = rval && ffindMarker(infile,0xff,0xd9,2L); fclose(infile); return rval;}

int isjpg(char *fname){ int rval; FILE *infile; rval = 0; infile = fopen(fname,"rb");

/* look for jpeg markers in first two bytes */ if(ffindMarker(infile,0xff,0xd8,2L)) rval = 1;

/* check last two bytes for end marker */ fseek(infile, -2, SEEK_END); rval = rval && ffindMarker(infile,0xff,0xd9,2L); fclose(infile); return rval;}

Page 26: Object and Class Creational Design Patterns

26

bmpSize()bmpSize()

void bmpSize(char *fname, long *width, long *height){ FILE *infile; long w,h; short bigindian; bigindian = ((char *)(&INDIANFLAG))[0]; /* determine endianess */

infile = fopen(fname,"rb"); fseek(infile,18,SEEK_SET); /* skip header header string */ fread(&w,sizeof(long),1,infile); fread(&h,sizeof(long),1,infile); if (bigindian) /* bmp are little indian format */ { swapLong(w,width); swapLong(h,height); } else { *width = w; *height = h; } fclose(infile);}

void bmpSize(char *fname, long *width, long *height){ FILE *infile; long w,h; short bigindian; bigindian = ((char *)(&INDIANFLAG))[0]; /* determine endianess */

infile = fopen(fname,"rb"); fseek(infile,18,SEEK_SET); /* skip header header string */ fread(&w,sizeof(long),1,infile); fread(&h,sizeof(long),1,infile); if (bigindian) /* bmp are little indian format */ { swapLong(w,width); swapLong(h,height); } else { *width = w; *height = h; } fclose(infile);}

Page 27: Object and Class Creational Design Patterns

27

dspEntry()dspEntry()

void dspEntry(DISPLAYOPTIONS* dsp, IMAGEINFO img){ int i; if(dsp.fieldlen > 0) { for( i = 0; i < dsp.fieldlen-1; i++) { switch (dsp.fields[i]) { case 'N' : case 'n' : printf("%s%s",img.filename, dsp.sep); break; case 'T' : case 't': printf("%s%s",img.imgtypename, dsp.sep); break; case 'W' : case 'w' : printf("%ld%s",img.width, dsp.sep); break; case 'H' : case 'h' : printf("%ld%s", img.height, dsp.sep); } }

void dspEntry(DISPLAYOPTIONS* dsp, IMAGEINFO img){ int i; if(dsp.fieldlen > 0) { for( i = 0; i < dsp.fieldlen-1; i++) { switch (dsp.fields[i]) { case 'N' : case 'n' : printf("%s%s",img.filename, dsp.sep); break; case 'T' : case 't': printf("%s%s",img.imgtypename, dsp.sep); break; case 'W' : case 'w' : printf("%ld%s",img.width, dsp.sep); break; case 'H' : case 'h' : printf("%ld%s", img.height, dsp.sep); } }

switch(dsp.fields[dsp.fieldlen-1]) { case 'N' : case 'n': printf("%s\n",img.filename); break; case 'T' : case 't' : printf("%s\n",img.imgtypename); break; case 'W' : case 'w' : printf("%ld\n",img.width); break; case 'H' : case 'h' : printf("%ld\n", img.height); } } }

switch(dsp.fields[dsp.fieldlen-1]) { case 'N' : case 'n': printf("%s\n",img.filename); break; case 'T' : case 't' : printf("%s\n",img.imgtypename); break; case 'W' : case 'w' : printf("%ld\n",img.width); break; case 'H' : case 'h' : printf("%ld\n", img.height); } } }

Page 28: Object and Class Creational Design Patterns

28

main()main()

void main(int argc, char *argv[]){ int i; if(argc == 1) dspUsage(); for(i = 1; i < argc; ++i) { int t; if(t = getOptionCode(argv[i]) { i = setOption(t, argv, i, &displayOptions); } else break; }

void main(int argc, char *argv[]){ int i; if(argc == 1) dspUsage(); for(i = 1; i < argc; ++i) { int t; if(t = getOptionCode(argv[i]) { i = setOption(t, argv, i, &displayOptions); } else break; }

for( ; i < argc; ++i) { imageType(argv[i],&currentImage); if(displayOptions.verbose || currentImage.imgtype != NOTYPE) { imageSize(&currentImage); dspEntry(displayOptions, currentImage); } } // for

} // main()

for( ; i < argc; ++i) { imageType(argv[i],&currentImage); if(displayOptions.verbose || currentImage.imgtype != NOTYPE) { imageSize(&currentImage); dspEntry(displayOptions, currentImage); } } // for

} // main()

Page 29: Object and Class Creational Design Patterns

29

imageType()imageType()

void imageType(char *img, IMAGEINFO *info){ int rval; info->filename = img; if(isjpg(img)) info->imgtype = JPEGTYPE; else if(isgif(img)) info->imgtype = GIFTYPE; else if(isbmp(img)) info->imgtype = BMPTYPE; else info->imgtype = NOTYPE;}

void imageType(char *img, IMAGEINFO *info){ int rval; info->filename = img; if(isjpg(img)) info->imgtype = JPEGTYPE; else if(isgif(img)) info->imgtype = GIFTYPE; else if(isbmp(img)) info->imgtype = BMPTYPE; else info->imgtype = NOTYPE;}

Page 30: Object and Class Creational Design Patterns

30

imageSize()imageSize()

void imageSize(IMAGEINFO *info){ switch (info->imgtype) { case JPEGTYPE : jpegSize(info->filename,&(info->width),&(info->height)); info->imgtypename = "JPG"; break; case BMPTYPE : bmpSize(info->filename,&(info->width),&(info->height)); info->imgtypename = "BMP"; break;

case GIFTYPE : gifSize(info->filename,&(info->width),&(info->height)); info->imgtypename = "GIF"; break;

case NOTYPE : info->width = info->height = 0; info->imgtypename = "XXX"; }}

void imageSize(IMAGEINFO *info){ switch (info->imgtype) { case JPEGTYPE : jpegSize(info->filename,&(info->width),&(info->height)); info->imgtypename = "JPG"; break; case BMPTYPE : bmpSize(info->filename,&(info->width),&(info->height)); info->imgtypename = "BMP"; break;

case GIFTYPE : gifSize(info->filename,&(info->width),&(info->height)); info->imgtypename = "GIF"; break;

case NOTYPE : info->width = info->height = 0; info->imgtypename = "XXX"; }}

Page 31: Object and Class Creational Design Patterns

31

buildOptions()buildOptions()

int buildOptions(int argc, char** argv, DISPLAYOPTIONS* result) { /* this function replaces the first loop in main() */ int i; result->sep =","; result->fields = "ntwh"; result->fieldlen = 4; result->verbose = 0; for(i = 1; i < argc; ++i) { int t; if(t = getOptionCode(argv[i]); i = setOption(t, argv, i, &displayOptions); else break; } return i; }

int buildOptions(int argc, char** argv, DISPLAYOPTIONS* result) { /* this function replaces the first loop in main() */ int i; result->sep =","; result->fields = "ntwh"; result->fieldlen = 4; result->verbose = 0; for(i = 1; i < argc; ++i) { int t; if(t = getOptionCode(argv[i]); i = setOption(t, argv, i, &displayOptions); else break; } return i; }