/
CMPE 135: Object-Oriented Analysis CMPE 135: Object-Oriented Analysis

CMPE 135: Object-Oriented Analysis - PowerPoint Presentation

tatyana-admore
tatyana-admore . @tatyana-admore
Follow
342 views
Uploaded On 2019-06-29

CMPE 135: Object-Oriented Analysis - PPT Presentation

and Design January 29 Class Meeting Department of Computer Engineering San Jose State University Spring 2019 Instructor Ron Mak wwwcssjsuedumak 1 Reminder By Wednesday January 30 Form teams ID: 760675

wood guitar builder string guitar wood string builder type inventory model top return guitarspec price guitars number class spec

Share:

Link:

Embed:

Download Presentation from below link

Download Presentation The PPT/PDF document "CMPE 135: Object-Oriented Analysis" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

Slide1

CMPE 135: Object-Oriented Analysis and DesignJanuary 29 Class Meeting

Department of Computer EngineeringSan Jose State UniversitySpring 2019Instructor: Ron Makwww.cs.sjsu.edu/~mak

1

Slide2

Reminder: By Wednesday, January 30

Form teams.Email me your team information.team nameteam members and email addresses

2

Slide3

3

Example: Rick’s Guitars

Inventory Management Application

for Rick’s GuitarsMaintain a guitar inventory.Locate guitars for customers.

UML class diagrams

Head First Object-Oriented

Analysis & Design

by Brett D. McLaughlin, et al.

O’Reilly, 2006.

Slide4

4

#include <string>using namespace std;class Guitar{public:    Guitar(string serial_number, double price,           string builder, string model, string type,           string back_wood, string top_wood)    : serial_number(serial_number), builder(builder), model(model),      type(type), back_wood(back_wood), top_wood(top_wood), price(price)    {}    string get_serial_number() const  { return serial_number; }    double get_price() const          { return price; }    void   set_price(float new_price) { price = new_price; }    string get_builder() const        { return builder; }    string get_model() const          { return model; }    string get_type() const           { return type; }    string get_back_wood() const      { return back_wood; }    string get_top_wood() const       { return top_wood; }private:    string serial_number, builder, model, type, back_wood, top_wood;    double price;};

Iteration #1: The Guitar Class

Whyprivate?

Guitar.h

Slide5

5

The Inventory Class

#include <list>#include "Guitar.h"using namespace std;class Inventory{public:    Inventory() {}    void add_guitar(string serial_number, double price,                    string builder, string model, string type,                    string back_wood, string top_wood);    Guitar *get_guitar(const string serial_number) const;    Guitar *search(Guitar *ideal_guitar);private:    vector<Guitar *> guitars;};

Inventory.h

Slide6

6

The Inventory Class, cont’d

void Inventory::add_guitar(string serial_number, double price,                           string builder, string model, string type,                           string back_wood, string top_wood){    Guitar *guitar = new Guitar(serial_number, price, builder,                               model, type, back_wood, top_wood);    guitars.push_back(guitar);}Guitar *Inventory::get_guitar(string serial_number) const{    list<Guitar *>::iterator it;    for (it = guitars.begin(); it != guitars.end(); it++)    {        Guitar *guitar = *it;        if (guitar->get_serial_number() == serial_number) return *it;    }    return nullptr;}

Inventory.cpp

Slide7

The Inventory Class, cont’d

7

Guitar *Inventory::search(Guitar *ideal_guitar){    list<Guitar *>::iterator it;    for (it = guitars.begin(); it != guitars.end(); it++)    {        Guitar *guitar = *it;        string builder = ideal_guitar->get_builder();        if (builder != guitar->get_builder())  continue;        string model = ideal_guitar->get_model();        if (model != guitar->get_model()) continue;        string type = ideal_guitar->get_type();        if (type != guitar->get_type()) continue;        string back_wood = ideal_guitar->get_back_wood();        if (back_wood!= guitar->get_back_wood()) continue;        string top_wood = ideal_guitar->get_top_wood();        if (top_wood != guitar->get_top_wood()) continue;        return *it; // found a match    }    return nullptr; // no match}

Ignore serial number since that's unique.Ignore price since that's unique.

Inventory.cpp

Slide8

FindGuitarTester

8

void initialize_inventory(Inventory *inventory){    inventory->add_guitar("11277", 3999.95, "Collings", "CJ", "acoustic",                          "Indian Rosewood", "Sitka");    inventory->add_guitar("V95693", 1499.95, "Fender", "Stratocastor", "electric",                         "Alder", "Alder");    inventory->add_guitar("V9512", 1549.95, "Fender", "Stratocastor", "electric",                          "Alder", "Alder");    inventory->add_guitar("122784", 5495.95, "Martin", "D-18", "acoustic",                          "Mahogany", "Adirondack");    inventory->add_guitar("76531", 6295.95, "Martin", "OM-28", "acoustic",                          "Brazilian Rosewood", "Adriondack");    inventory->add_guitar("70108276", 2295.95, "Gibson", "Les Paul", "electric",                          "Mahogany", "Maple");    inventory->add_guitar("82765501", 1890.95, "Gibson", "SG '61 Reissue",                          "electric", "Mahogany", "Mahogany");    inventory->add_guitar("77023", 6275.95, "Martin", "D-28", "acoustic",                          "Brazilian Rosewood", "Adirondack");    inventory->add_guitar("1092", 12995.95, "Olson", "SJ", "acoustic",                          "Indian Rosewood", "Cedar");    inventory->add_guitar("566-62", 8999.95, "Ryan", "Cathedral", "acoustic",                          "Cocobolo", "Cedar");    inventory->add_guitar("6 29584", 2100.95, "PRS", "Dave Navarro Signature",                          "electric", "Mahogany", "Maple");}

FindGuitarTester.cpp

Slide9

The FindGuitarTester Class, cont’d

9

int main(){    // Set up Rick's guitar inventory.    Inventory *inventory = new Inventory();    initialize_inventory(inventory);    Guitar *what_erin_likes = new Guitar("", 0, "fender", "Stratocastor",                                         "electric", "Alder", "Alder");    Guitar *guitar = inventory->search(what_erin_likes);    if (guitar != nullptr)    {        cout << "Erin, you might like this "             << guitar->get_builder() << " "             << guitar->get_model() << " "             << guitar->get_type() << " guitar:\n   "             << guitar->get_back_wood() << " back and sides,\n   "             << guitar->get_top_wood() << " top.\nYou can have it for only $"             << guitar->get_price() << "!";    }    else    {        cout << "Sorry, Erin, we have nothing for you.";    }}

Demo

FindGuitarTest.cpp

Slide10

10

Problems!

Case-sensitive string comparisons.

Make them case insensitive.

Badly used string fields.

Replace them with enumerated types.

Assumes at most only one guitar match.

Return a list of matching guitars.

Slide11

11

Take roll!

Slide12

Iteration #2: Remove String Fields

There are only a limited number each of guitar builders, types, and woods.Therefore, using the string type for those attributes is too general and prone to errors.Use enumerated types instead!We’ll assume that model names keep changing, so we’ll keep that attribute as a string.For each enumerated type, overload operator << to print an enumerated value as a string.

12

Slide13

13

Iteration #2: Remove String Fields, cont’d

#include <iostream>using namespace std;enum class Builder{    FENDER, MARTIN, GIBSON, COLLINGS, OLSON, RYAN, PRS, ANY,};inline ostream& operator <<(ostream& ostr, const Builder builder){    switch (builder)    {        case Builder::FENDER:   ostr << "Fender";   break;        case Builder::MARTIN:   ostr << "Martin";   break;        case Builder::GIBSON:   ostr << "Gibson";   break;        case Builder::COLLINGS: ostr << "Collings"; break;        case Builder::OLSON:    ostr << "Olson";    break;        case Builder::RYAN:     ostr << "Ryan";     break;        case Builder::PRS :     ostr << "PRS";      break;        default:                ostr << "Unspecified";    }    return ostr;}

Builder.h

Slide14

14

Iteration #2: Remove String Fields, cont’d

#include <iostream>using namespace std;enum class Type{    ACOUSTIC, ELECTRIC};inline ostream& operator <<(ostream& ostr, const Type type){    switch (type)    {        case Type::ACOUSTIC: ostr << "acoustic"; break;        case Type::ELECTRIC: ostr << "electric"; break;        default:             ostr << "unspecified";    }    return ostr;}

Type.h

Slide15

15

Iteration #2: Remove String Fields, cont’d

#include <iostream>using namespace std;enum class Wood{    INDIAN_ROSEWOOD, BRAZILIAN_ROSEWOOD, MAHOGANY, MAPLE,    COCOBOLO, CEDAR, ADIRONDACK, ALDER, SITKA,};inline ostream& operator <<(ostream& ostr, const Wood wood){    switch (wood)    {        case Wood::INDIAN_ROSEWOOD:    ostr << "Indian Rosewood";     break;        case Wood::BRAZILIAN_ROSEWOOD: ostr << "Brazilian Rosewood";  break;        case Wood::MAHOGANY:           ostr << "Mahogany";            break;        case Wood::MAPLE:              ostr << "Maple";               break;        case Wood::COCOBOLO:           ostr << "Cocobolo";            break;        case Wood::CEDAR:              ostr << "Cedar";               break;        case Wood::ADIRONDACK:         ostr << "Adirondack";          break;        case Wood::ALDER:              ostr << "Alder";               break;        case Wood::SITKA:              ostr << "Sitka";               break;        default:                       ostr << "unspecified";    }    return ostr;}

Wood.h

Slide16

Iteration #2: Remove String Fields, cont’d

16

class Guitar{public:    Guitar(string serial_number, double price,           Builder builder, string model, Type type,           Wood back_wood, Wood top_wood)    : serial_number(serial_number), model(model), price(price),      builder(builder), type(type), back_wood(back_wood), top_wood(top_wood)    {}    string  get_serial_number() const  { return serial_number; }    double  get_price() const          { return price; }    void    set_price(float new_price) { price = new_price; }    Builder get_builder() const        { return builder; }    string  get_model() const          { return model; }    Type    get_type() const           { return type; }    Wood    get_back_wood() const      { return back_wood; }    Wood    get_top_wood() const       { return top_wood; }private:    string serial_number, model;    double price;    Builder builder;    Type type;    Wood back_wood, top_wood;};

Guitar.h

Slide17

Iteration #2: Remove String Fields, cont’d

17

#include <vector>#include "Guitar.h"#include "Builder.h"#include "Type.h"#include "Wood.h"using namespace std;class Inventory{public:    Inventory() {}    void add_guitar(string serial_number, double price,                    Builder builder, string model, Type type,                    Wood back_wood, Wood top_wood);    Guitar *get_guitar(string serial_number);    vector<Guitar *> search(Guitar *ideal_guitar);

Inventory.h

Slide18

Iteration #2: Remove String Fields, cont’d

18

private:    vector<Guitar *> guitars;    string to_lower(string str);};inline string Inventory::to_lower(string str){    transform(str.begin(), str.end(), str.begin(), ::tolower);    return str;}

Inventory.h

We add a small inline function that sets

to lower-case all the letters of a string.

Slide19

Iteration #2: Return Multiple Matches

19

list<Guitar *> Inventory::search(Guitar *ideal_guitar){    list<Guitar *> matching_guitars;    list<Guitar *>::iterator it;    for (it = guitars.begin(); it != guitars.end(); it++)    {        Guitar *guitar = *it;        Builder builder = ideal_guitar->get_builder();        if (builder != guitar->get_builder()) continue;        if (   to_lower(ideal_guitar->get_model())            != to_lower(guitar->get_model())) continue;        Type type = ideal_guitar->get_type();        if (type != guitar->get_type()) continue;        Wood back_wood = ideal_guitar->get_back_wood();        if (back_wood!= guitar->get_back_wood()) continue;        Wood top_wood = ideal_guitar->get_top_wood();        if (top_wood != guitar->get_top_wood()) continue;        matching_guitars.push_back(guitar);    }    return matching_guitars;}

Inventory.cpp

Slide20

Iteration #2: Return Multiple Matches, cont’d

20

int main(){    // Set up Rick's guitar inventory.    Inventory *inventory = new Inventory();    FindGuitarTester::initialize_inventory(inventory);    Guitar *what_erin_likes = new Guitar("", 0, Builder::FENDER,                                         "stratocastor", Type::ELECTRIC,                                         Wood::ALDER, Wood::ALDER);    list<Guitar *> matching_guitars = inventory->search(what_erin_likes);    if (matching_guitars.size() > 0)    {        cout << "Erin, you might like these guitars:" << endl;        list<Guitar *>::iterator it;        for (it = matching_guitars.begin(); it != matching_guitars.end(); it++)        {            Guitar *guitar = *it;            cout << guitar->get_builder() << " "                 << guitar->get_model() << " "                 << guitar->get_type() << " guitar:\n   "                 << guitar->get_back_wood() << " back and sides,\n   "                 << guitar->get_top_wood() << " top.\nYou can have it for only $"                 << guitar->get_price() << "!" << endl;            cout << "  ----" << endl;        }    }    else    {        cout << "Sorry, Erin, we have nothing for you.";    }}

FindGuitarTest.cpp

Demo

Slide21

21

Still More Problems!

Customers don’t always know

all the attributes of the guitar they want.

Do we need wildcard search fields?

Rick may decide to

add more

guitar attributes

to his inventory.

Example: Number of guitar strings

The

Inventory::search()

method

is going to get complicated really fast.

It will be difficult to maintain if we

have to add more guitar attributes.

Slide22

22

What’s Changing?

The attributes of a guitar can change.

Rick can decide to add, remove, or modify them.

The inventory keeps track of guitars,

not guitar attributes.

Therefore,

the inventory code should not change

when the guitar attributes change.

Slide23

What’s Changing? cont’d

If we encapsulate what changes, we can isolate the changes from the rest of the code.What changes? The guitar attributes.Goal: When the guitar attributes change, the rest of the code does not need to change.

23

Slide24

24

The Solution: Encapsulation

Create a new

GuitarSpec

class that

represents the attributes of a guitar.

Only the

GuitarSpec

class needs to change

if the attributes change.

Therefore, the

GuitarSpec

class

encapsulates

the changes

and

isolates

them

from the rest of the code.

Slide25

25

Iteration #3: GuitarSpec Class

class GuitarSpec{public:    GuitarSpec(Builder builder, string model, Type type,               Wood back_wood, Wood top_wood)    : model(model), builder(builder), type(type),      back_wood(back_wood), top_wood(top_wood)    {}    Builder get_builder() const   { return builder; }    string  get_model() const     { return model; }    Type    get_type() const      { return type; }    Wood    get_back_wood() const { return back_wood; }    Wood    get_top_wood() const  { return top_wood; }private:    string model;    Builder builder;    Type type;    Wood back_wood, top_wood;};

GuitarSpec.h

Slide26

26

Iteration #3: GuitarSpec Class, cont’d

This UML class diagram shows that:A Guitar aggregates a GuitarSpec.A GuitarSpec is part of a Guitar.The relationship is one-to-one.

From:

Head First Object-Oriented Analysis & Design

, O’Reilly, 2006.

Slide27

27

Iteration #3: GuitarSpec Class, cont’d

class Guitar{public:    Guitar(string serial_number, double price,           Builder builder, string model, Type type,           Wood back_wood, Wood top_wood)    : serial_number(serial_number), price(price),      spec(new GuitarSpec(builder, model, type, back_wood, top_wood))    {}    string      get_serial_number() const  { return serial_number; }    double      get_price() const          { return price; }    void        set_price(float new_price) { price = new_price; }    GuitarSpec *get_spec() const           { return spec; }private:    string serial_number, model;    double price;    GuitarSpec *spec;};

Guitar.h

Slide28

Iteration #3: GuitarSpec Class, cont’d

28

class Inventory{public:    Inventory() {}    void add_guitar(string serial_number, double price,                    Builder builder, string model, Type type,                    Wood back_wood, Wood top_wood);    Guitar *get_guitar(string serial_number);    vector<Guitar *> search(GuitarSpec *ideal_spec);private:    vector<Guitar *> guitars;    string to_lower(string str);};

Inventory.h

Slide29

Iteration #3: GuitarSpec Class, cont’d

29

vector<Guitar *> Inventory::search(GuitarSpec *ideal_spec){    vector<Guitar *> matching_guitars;    for (Guitar *guitar : guitars)    {        GuitarSpec *guitar_spec = guitar->get_spec();        // Ignore serial number since that's unique.        // Ignore price since that's unique.        Builder builder = ideal_spec->get_builder();        if (builder != guitar_spec->get_builder()) continue;        string model = to_lower(ideal_spec->get_model());        if (   (model != "")            && (model != to_lower(guitar_spec->get_model()))) continue;        Type type = ideal_spec->get_type();        if (type != guitar_spec->get_type()) continue;        Wood back_wood = ideal_spec->get_back_wood();        if (back_wood!= guitar_spec->get_back_wood()) continue;        Wood top_wood = ideal_spec->get_top_wood();        if (top_wood != guitar_spec->get_top_wood()) continue;        matching_guitars.push_back(guitar);    }    return matching_guitars;}

Inventory.cpp

Slide30

Iteration #3: GuitarSpec Class, cont’d

30

GuitarSpec *what_erin_likes =    new GuitarSpec(Builder::FENDER, "stratocastor",                   Type::ELECTRIC, Wood::ALDER, Wood::ALDER);vector<Guitar *> matching_guitars = inventory->search(what_erin_likes);

FindGuitarTest.cpp

Slide31

Encapsulation, Again

By creating the GuitarSpec class, have we done a good enough job ofisolating changes to the guitar attributes?What if Rick wants to add the number of strings to the guitar attributes?How will that change affect the code?

31

Slide32

Iteration #4: New Attribute

32

class GuitarSpec{private:    string model;    Builder builder;    Type type;    int string_count;    Wood back_wood, top_wood;public:    GuitarSpec(Builder builder, string model, Type type,               int string_count, Wood back_wood, Wood top_wood)    : model(model), builder(builder), type(type), string_count(string_count),      back_wood(back_wood), top_wood(top_wood)    {}    Builder get_builder() const      { return builder; }    string  get_model() const        { return model; }    Type    get_type() const         { return type; }    int     get_string_count() const { return string_count; }    Wood    get_back_wood() const    { return back_wood; }    Wood    get_top_wood() const     { return top_wood; }};

GuitarSpec.h

Slide33

Iteration #4: New Attribute, cont’d

33

class Inventory{public:    Inventory();    void add_guitar(string serial_number, double price,                    Builder builder, string model, Type type,                    int string_count, Wood back_wood, Wood top_wood);    Guitar *get_guitar(string serial_number);    list<Guitar *> search(GuitarSpec *ideal_spec);private:    list<Guitar *> guitars;    string to_lower(string str);};

Inventory.h

Slide34

Iteration #4: New Attribute, cont’d

34

list<Guitar *> Inventory::search(GuitarSpec *ideal_spec){    list<Guitar *> matching_guitars;    list<Guitar *>::iterator it;    for (it = guitars.begin(); it != guitars.end(); it++)    {        Guitar *guitar = *it;        GuitarSpec *guitar_spec = guitar->get_spec();        ...        int string_count = ideal_spec->get_string_count();        if (string_count != guitar_spec->get_string_count()) continue;        ...        matching_guitars.push_back(guitar);    }    return matching_guitars;}

Inventory.cpp

Slide35

35

Time to Refactor Again!

Refactor

: To modify the structure of your code

without

modifying its behavior in order to improve it in some way.

Why should the

Inventory

class

also have to change?

If the guitar attributes change, such as adding the number of guitar strings, then the search method needs to change.

The customer may want to search for a guitar

that matches a certain number of strings.

Slide36

Time to Refactor Again! cont’d

We need to move the guitar matching algorithm out of the Inventory class (the search() method) and into the new GuitarSpec class in order to completely encapsulate the changes to the search method.We delegate comparing two GuitarSpec objects to the GuitarSpec class itself.Delegate: When an object needs to perform a task, it asks another object to perform the task on its behalf.

36

Slide37

37

Iteration #5: Delegate Matching

class GuitarSpec{public:    GuitarSpec(Builder builder, string model, Type type,               int string_count, Wood back_wood, Wood top_wood);    Builder get_builder() const;    string  get_model() const;    Type    get_type() const;    int     get_string_count() const;    Wood    get_back_wood() const;    Wood    get_top_wood() const;    bool matches(GuitarSpec *other_spec);private:    string model;    Builder builder;    Type type;    int string_count;    Wood back_wood, top_wood;    string to_lower(string str);};

GuitarSpec.h

inline string

GuitarSpec

::

to_lower

(string

str

)

{

    transform(

str.begin

(),

str.end

(),

str.begin

(), ::

tolower

);

    return

str

;

}

Slide38

Iteration #5: Delegate Matching, cont’d

38

bool GuitarSpec::matches(GuitarSpec *other_spec){    if (builder != other_spec->builder) return false;    if (   (model != "")        && (to_lower(model) != to_lower(other_spec->model))) return false;    if (type != other_spec->type) return false;    if (string_count != other_spec->string_count) return false;    if (back_wood != other_spec->back_wood) return false;    if (top_wood != other_spec->top_wood) return false;    return true;}

This code was originallyin the search() methodof class Inventory.

GuitarSpec.cpp

Slide39

39

Iteration #5: Delegate Matching, cont’d

list<Guitar *> Inventory::search(GuitarSpec *ideal_spec){    list<Guitar *> matching_guitars;    list<Guitar *>::iterator it;    for (it = guitars.begin(); it != guitars.end(); it++)    {        Guitar *guitar = *it;        GuitarSpec *guitar_spec = guitar->get_spec();        if (guitar_spec->matches(ideal_spec))        {            matching_guitars.push_back(guitar);        }    }    return matching_guitars;}

This code is a lot easier to read!

Now Inventory::search()delegates the matching algorithm to the GuitarSpec object.

Inventory.cpp

Slide40

Encapsulation Success!

Now whenever the guitar attributes change, we only have to modify the GuitarSpec class.No other classes need to change.We don’t count the test class FindGuitarTester.

40