Software Construction Assignment: Assignment 2 (Worth 200 Points)

profilefarzadbigz
FindingClasses.pptx

NDSU CSCI 717 Software Construction

Class Design

Textbooks

Bertrand Meyer. Object-Oriented Software Construction, 2nd Edition, Prentice-Hall PTR, 1997. Chapters 22 and 23.

Steve McConnell. Code Complete: A Practical Handbook of Software Construction. 2nd Edition. Microsoft Press, 2004. Chapter 6.

2

Finding Classes

Central decision in OOSC

It takes talent and experience, not to mention luck.

You should not expect too much – expecting infallible recipes for finding classes is unrealistic

Motivation of a methodological discussion

Indicate some good ideas

Draw your attention to some illuminating precedents

Alert you to some known pitfalls

Selection technique

What to consider

What to reject

4

Finding Classes from Requirements

The elevator will close its door before it moves to another floor.

Can you find any classes?

5

Nouns & Verbs in Requirements Doc

Function-oriented design

Concentrate on the verbs – actions

Move, close

Object-oriented design

Underline the nouns – objects

Elevator, Door, Floor – voila

Danger!

Requirements in a natural language are open to nuance, personal variation and ambiguity

6

Avoiding Useless Classes

The nouns method covers some classes of the final design.

The method includes many “false alarms” also

Concepts should not yield classes

Do we need class Door?

7

Do We Need Class Door? No

The only relevant property: opened/closed

It suffices to have query/commands in Elevator

door_open: BOOLEAN;

close_door is

ensure not door_open

end;

open_door is

ensure door_open

end

8

Do We Need Class Door? Maybe

The notion of door may be important enough to justify a separate class.

Do not expect grammatical criteria to be of more than superficial help. Turn instead to the ADT theory

Theory of ADTs – helps ask customers the right questions

Is “door” a separate data type with its own clearly identified operations, or

Are all the operations on doors already covered by operations on other data types such as Elevator?

9

Do We Need Class Floor?

Floors are definitely an important data abstraction for an elevator system.

What properties?

10

Is a New Class Necessary?

Another example of a noun which may or may not give a class in the elevator example is floor.

Unnecessary - floor properties may be entirely covered by those of integers.

Floor number, distance between two floors

Appropriate - significant operations not covered by those of integers

Some floors may have special access rights defining who can visit them

Need access rights and associated procedures

More properties: subtract/compare two floors, but not to add or multiply them.

11

Is a New Class Necessary?

A class does not just cover physical "objects" in the naïve sense. It describes an abstract data type a set of software objects characterized by well defined operations and formal properties of these operations.

A type of real world objects may or may not have a counterpart in the software in the form of a type of software objects a class.

When you are assessing whether a certain notion should yield a class or not, only the ADT view can provide the right criterion: Do the objects of the system under discussion exhibit enough specific operations and properties of their own, relevant to the system and not covered by existing classes?

12

Is a New Class Necessary?

The aim of systems analysis is not to "model the world". This may be a task for philosophers, but the builders of software systems could not care less, at least for their professional activity

The task of analysis is to model that part of the world which is meaningful for the software under study or construction. This principle is reinforced by the ADT approach - objects are only defined by what we can do with them

Principle of Selfishness - If an operation or property of an object is irrelevant to the purposes of the system, then it should not be included in the result of your analysis however interesting it may be for other purposes

For a census processing system, the notion of PERSON may have features mother and father; but for a payroll processing system which does not require information about the parents, every PERSON is an orphan

13

Is a New Class Necessary?

If all of the operations and properties that you can identify for a type of objects are irrelevant, or are already covered by the operations and properties of a previously identified class, then that object type itself is irrelevant: it must not yield a class.

This explains why an elevator system might not include FLOOR as a class because (as noted earlier) from the point of view of the elevator system floors have no relevant properties other than those of the associated integer numbers, whereas a

Computer Aided Design system designed for architects will have a FLOOR class since in that case the floor has several specific attributes and routines.

14

ADT View as the Right Criterion

Do the objects exhibit enough specific operations and properties of their own, relevant to the system and not covered by existing classes?

15

Missing Important Classes

Not only can nouns suggest notions which do not yield classes: they can also fail to suggest some notions which should definitely yield classes

Suppose a requirements has a following sentence: “A database record must be created every time the elevator moves from one floor to another.”

Noun “record” suggests Database-Record class

Any class missing?

16

Missing Important Classes - cont

We may totally miss a more important data abstraction: the notion of a move between two floors.

Move between two floors is important which could be of the form-

class MOVE feature

initial, final: FLOOR; -- or INT if no Floor class

record (d: Database) is …

… other features …

end

17

Why Are Classes Missing

Flexibility and ambiguity of human language

Move is an important class, which a grammar based method would miss because of the phrasing of the above sentence.

Of course if the sentence had appeared as

A database record must be created for every move of the elevator from one floor to another.

Here move would have been counted as a “noun” and would have yielded a class.

Therefore, some crucial abstractions may not be directly deducible from the requirements

18

Why Are Classes Missing

Another reason for overlooking classes is that some crucial abstractions may not be directly deducible from the requirements.

Given the following requirement for text editor program: “The editor must allow its users to insert or delete a line at the current cursor position.”

Naïve designer may his/her attention to the trivial notions of "cursor" and "position" while missing the command abstractions (line insertion and line deletion).

19

Why Are Classes Missing

A third major cause of missed classes, a strategy that uses requirements document as the basis for analysis often overlooks reuse

Some abstractions are likely to be found in existing software, not in the reqs doc for a new project.

Existing software can and should influence new developments.

When faced with a new software project, the object oriented software developer does not accept the requirements document as the alpha and omega of wisdom about the problem, but combines it with knowledge about previous developments and available software libraries.

If necessary, he/she will criticize the requirements document and propose updates and adaptations which will facilitate the construction of the system; sometimes a minor change, or the removal of a facility which is of limited interest to the final users, will produce a dramatic simplification by making it possible to reuse an entire body of existing software and, as a result, to decrease the development time by months.

The corresponding abstractions are most likely to be found in the existing software, not in the requirements document for the new project.

20

Discovery and Rejection

Lesson 1: Do not put too much trust in a requirements document; do not put any trust in grammatical criteria.

Lesson 2: Eliminating bad ideas as important as finding good ones

Concepts may initially appear promising but end up not justifying a class of their own.

We need criteria for rejecting candidate classes

21

How to find classes?

"How to find the classes" means two things:

How to come up with candidate abstractions?

How to unmask the inadequate among them?

These two tasks are not executed one after the other; instead, they are constantly interleaved. Like a gardener, the object oriented designer must all the time nurture the good plants and weed out the bad.

Class Elicitation Principle

Elicitation is a dual process: suggestion, rejection.

22

Danger Signals

Signs of a bad choice of class, not proof!

The grand mistake – designing a class that isn’t

Principle of OO Software Construction is to build modules around object types, not functions - each class corresponds to a meaningful data abstraction

“This class prints the results”

“This class parses the input”

“This class does …”

Writing a module as class ... feature ... end does not make it a true class; it may just be a routine in disguise.

A class is not supposed to do one thing but to offer a number of services on objects of a certain type.

23

Danger Signals - cont

Imperative class names

A verb in the imperative or infinitive, e.g. Parse or Print class names should catch your attention

Either its name is wrong or it ‘does one thing’

Occasionally you may find that the class is right. Then its name is wrong. This is an "absolute positive" rule

Class name rule

A noun, possibly qualified.

An adjective (only for a deferred class describing a structural property), e.g. Comparable

Possible exception

Command classes – action abstractions

Stick to the rule – LineDeletion vs DeleteLine

24

Danger Signals - cont

Single-routine classes

Only one exported routine, possibly calling a few non-exported ones.

Inheritance should be considered

Possible exception: interactive command

Premature classification

Instances vs heirs

SanFrancisco and Houston inherit from City

Rather have the SanFrancisco and Houston as names of instances of City.

25

Danger Signals - cont

No-command classes

Classes with no routines or Queries routines only without commands

Need to probe

A class may describe non-modifiable objects – e.g. obtained from the outside world (sensor)

Some classes are meant for encapsulating facilities e.g. constants, Java String

26

Danger Signals - cont

Mixed abstractions

Another sign of an imperfect design is a class whose features relate to more than one abstraction.

EmployeeCensus ‘is-a’ ListContainer

Meilir PageJones uses the term connascence (defined in dictionaries as the property of being born and having grown together) to describe the relation that exists between two features when they are closely connected, based on a criterion of simultaneous change: a change to one will imply a change to the other.

You should minimize connascence across class libraries; but features that appear within a given class should all be related to the same clearly identified abstraction.

Class consistency principle: all the features of a class must pertain to a single, well-identified abstraction.

27

The Ideal Class

Clearly associated abstraction

Name: noun or adjective,

Adequately characterizing the abstraction.

Class represents a set of run-time objects

Some meant to have only one instance are acceptable

Queries for finding out properties of an instance.

Commands for changing the state of an instance.

Abstract properties can be stated, describing:

How various queries relate to each other (invariant)

Under what conditions features are applicable (preconds)

How commands affects query results (postconds)

28

General Heuristics for Finding Classes

Three broad categories of classes:

Analysis class: describes a data abstraction directly drawn from the model of the external system.

Plane in a traffic control system,

Paragraph in a document processing system

Part in a inventory control system.

Implementation class: describes a data abstraction introduced for the internal needs of the algorithms in the software

LinkedList or Array.

Design class: In-between, a design class describes an architectural choice

Design patterns

29

29

implementation classes and design classes belong to the solution space

analysis classes belong to the problem space.

Analysis classes and design classes describe high-level concepts

Other Sources of Classes

Previous developments

As you write applications, accumulate classes to facilitate later developments.

Adaptation through inheritance

An existing class does not exactly suit present need; some adaptation may be necessary.

Make sure to preserve clients as per Open-Close principle.

Evaluating candidate decompositions

Do they constitute autonomous, coherent modules?

Do they have too much communication with others?

Hints from other approaches (e.g. non-OO: ER modeling)

Use cases

CRC cards

30

30

CRC (Class, Responsibility, Collaboration): designers discuss potential classes in terms of their responsibilities and how they communicate.

Sources of Class Ideas

Source of Ideas What to look for
Existing libraries Classes that address needs of the application or describe concepts relevant to the application.
Requirements Document Terms that occur frequently. Terms to which the text devotes explicit definitions. Terms not defined precisely but taken for granted throughout the doc Disregard grammatical categories
Discussions with customers/ future users Important domain abstractions Specific jargon of the domain. Conceptual and material objects.

31

Sources of Class Ideas - cont

Source of Ideas What to look for
Doc for other systems in the same domain Important abstractions of the domain Specific jargon of the domain. Useful design abstractions
Non-O-O systems or system descriptions Data elements passed as arguments between various components Shared memory areas Important files. Record/structure types Entities in ER modeling.

32

Sources of Class Ideas - cont

Source of Ideas What to look for
Discussions with experienced designers Design classes successfully used in previous developments of a similar nature.
Algorithms and data structure literature Known data structures supporting efficient algorithms.
O-O design literature Applicable design patterns

33

Good Class Interfaces

Important step in creating high-quality classes is creating a good interface.

Consists of creating a good abstraction for the interface to represent and ensuring that details remain hidden behind the abstraction.

Command-Query Separation Principle

Good Abstraction

Good Encapsulation

How Many Arguments for a Feature

Class Size

Dealing with Abnormal Cases

34

Command-Query Separation Principle

Some side effects are harmless and necessary

Functions modify the state (affecting visible features) but then restore the original state during execution.

Change the state of the object only affects properties invisible to clients.

Foolish to dismiss side-effect-full style as thoughtless

Abstract side effect

A concrete side effect that can change the value of a non-secret query

CQSP - only prohibits abstract side effects

Brings referential transparency back

Yields a clean style of design - simple and readable

35

Good Abstraction

Be sure what abstraction the class is implementing

A class interface provides an abstraction of the implementation that’s hidden behind the interface

A classes routines should be cohesive group sharing a common responsibility.

Example of a good abstraction of a class

Employee class containing data describing employee’s name, address, phone # and so on. It would offer services to initialize and use an employee.

Every routine is working towards a consistent end.

36

Good Abstraction: Employee

Class Employee {

public:

// public constructors and destructors

Employee();

Employee(FullName name, String address,

String workPhone, String homePhone,

TaxId taxIdNumber,JobClassification jobClass);

Virtual ~Employee();

//public routines

FullName GetName() const;

String GetAddress() const;

String GetWorkPhone() const;

String GetHomePhone() const;

TaxId GetTaxIdNumber() const;

JobClassification GetJobClassification() const;

}

37

Good Abstraction

Present consistent, cohesive level of abs.

Each class should implement one and only one ADT

If a class implements more than one ADT, it is time to decompose the class so each class represents one ADT.

Example of a class Interface with Mixed Levels of Abstraction

The class is presenting two ADTs: an Employee and a ListContainer. Also, the test for inheritance fails

“EmployeeCensus” is a ListContainer” does not make logical sense

The fact container class is used should be hidden from rest of the program.

38

Example of a class Interface with Mixed Levels of Abstraction

class EmployeeCensus: public ListContainer

{

public:

void AddEmployee(Employee emp);

void RemoveEmployee(Employee emp);

Employee NextItemInList();

Employee FirstItem();

Employee LastItem();

private:

.......

}

39

Abstraction of these routines is at “employee level”

Abstraction of these routines is at “list” level

class EmployeeCensus

{

public:

void AddEmployee(Employee emp);

void RemoveEmployee(Employee emp);

Employee NextIEmployee();

Employee FirstEmployee();

Employee LastEmployee();

private:

ListContainer m_EmployeeList;

}

40

The abstraction of all these routines is at “employee” level

That the class uses the ListContainer library is now hidden

Good Abstraction

Provide services in pairs with their opposites

Check each public routine to determine whether you need it’s complement.

Turn on/off, activate/deactivate, …

Move unrelated information to another class

If half the routines use half the data and other half routines use other data, then it is time to decompose the class into two separate classes.

41

Good Abstraction

Make interfaces programmatic rather than semantic when possible

Each interface has a programmatic part as well as a semantic part.

Programmatic parts – data types, other interface attributes

Semantic parts – “RoutineA must be called before RoutineB”. They are not enforceable by compiler.

Semantic part should be documented in comments.

Look for opportunities to convert semantic part to “Assert” statements (programmatic part).

42

Good Abstraction

Beware of erosion of interface’s abstraction under modification

Extending and modifying the class might require additional functionality.

The additional functionality may not necessarily belong the class.

Employee class evolving to become something like in the next slide

No logical connection between zipcode and employee

No logical connection between phone # and employee

SQL queries details are at a much more lower level of detail than Employee and should not be here.

43

Employee: Eroding under Maintenance

Class Employee {

public:

//public routines

FullName GetName() const;

Address GetAddress() const;

PhoneNumber GetWorkNumber() const;

bool IsJobClassificationValid(JobClassification jobClass);

bool IsZipCodeValid(Address address);

bool IsPhoneNumberValid(PhoneNumber phoneNumber);

SqlQuery GetQueryToCreateNewEmployee() const;

SqlQuery GetQueryToModifyEmployee() const;

SqlQuery GetQueryToRetrieveEmployee() const;

}

44

Good Encapsulation

Abstraction helps to manage complexity by allowing you to ignore implementation details

Encapsulation is the enforcer that prevents you from looking at details even if you want.

Without encapsulation, abstraction tends to breakdown.

Both are complementary and necessary. You can not have just one of them.

45

Good Encapsulation

Minimize accessibility of classes and members

Favor the strictest level of privacy that is workable

What best preserves the integrity of the abstraction?

E.g. Don’t put a routine into the public interface just because it uses only public routines

Don’t expose member data in public

Avoid putting private impl. details into the interface

Don’t make assumptions about the clients, unless documented in the interface

A class should be designed to adhere to the class contract implied in class interface

Favor read time convenience to write time convenience

Code is read (used) far more times than it’s written.

Speeding up code writing at the expense of well thought out good code is false economy. Example, not using Object type as a parameter in equals( ) method.

46

Good Encapsulation

Be very wary of semantic violations of encapsulation

Not calling Class A’s InitializeOperation( ) routine because you know that Class A’s PerformFirstOperation( ) routine calls it automatically.

Not calling Class A’s Terminate( ) routine because you know that ClassA’s PerformFinalOperation( ) routine has already called it.

The problem with above examples is that client code is dependent not on the class’s public interface instead on class’ private implementation.

47

Good Encapsulation

Watch for Coupling that’s too tight

Minimize accessibility of classes and members

Avoid friend classes, because they are tightly coupled

Make data private rather than protected in the base class

Avoid exposing member data in a class’s public interface

Be wary of semantic violations of encapsulation

48

Design and Implementation Issues

49

Containment (“has-a relationship”)

The idea that a class contains a primitive data type or object

Implement “has-a” through containment

Employee “has-a” name, “has-a” phone number ….

Accomplished by making them data members of Employee class

Implement “has-a” through private inheritance as a last resort

Privately inheriting from the contained object. (supported in C++ not in Java)

To allow containing class to access protected members functions and data of the class it’s contained.

50

50

Containment (continued)

Be critical of classes that contain more than about seven data members

7± 2 is the number of discrete items a person can remember while performing other tasks

If a class contains more than 7 data members, consider decomposing into number of smaller classes

51

Inheritance (“is-a” relationship)

The idea that one class is a specialization of another class

The purpose is to create simpler code by defining a base class that specifies common elements of two or more derived classes

Common elements – data members, routines, data types

Inheritance helps to avoid repeat the code and data in multiple locations

52

Inheritance

When you decide to use inheritance, need to consider the following decisions

For each member routine,

Will it be visible to derived class?

Will it have a default implementation?

Will the default implementation be overridden

For each data member (variables, constants, enumerations ..)

Will the data member be visible to derived classes?

53

Inheritance

Ins and outs of making decisions

Implement “is-a” through public inheritance

New class is a specialized version of older class

Derived class should adhere completely to the same interface contract defined by base class.

If derived class is not going to adhere to the contract the inheritance is not the right choice, consider containment.

Design and document for inheritance or prohibit it

If a class isn’t designed to be inherited from, make the members non-virtual in C++, final in java

54

Inheritance

Adhere to the Liskov Substitution Principle (LSP)

“You shouldn’t inherit from a base class unless the derived class truly “is-a” more specific version of the base class” – Barbara Liskov

Subclasses must be usable through the base class interface without the need for the user to know the difference

All routines defined in base class should mean the same thing when used in the derived class

55

Inheritance

Be sure to inherit only what you want to inherit

Inherited routines come in three basic flavors:

Abstract overridable routine – derived class inherits the public interface only no implementation

Overridable routine – derived class inherits public interface and default implementation but allowed to override

Non-overridden routine – derived class inherits public interface and default implementation and not allowed to override.

If you want to use a class implementation but not it’s interface then consider containment.

56

Inheritance

Don’t override a non-overridden member function

Don’t reuse names of non-overridden base class routines in derived classes

Move common interfaces, data, and behavior as high as possible in the inheritance

Be suspicious of classes of which there is only one instance (Singleton is an exception to this rule)

Be suspicious of base classes of which there is only one derived class

The best way to prepare for future sub-classes is not to design extra layers of base classes that might be needed some day.

Do not create any more inheritance structure than necessary.

57

Inheritance

Be suspicious of classes that override a routine and do nothing inside the derived routine

A Cat class containing a scratch() routine.

Creating a new class – ScratchLessCat that is a sub-class of Cat. But as ScrachLessCat can’t scratch, so overriding scratch( ) routine to do nothing.

Violates abstraction presented in Cat class by changing interface’s semantics

Difficult to maintain such code

58

Inheritance

Avoid deep inheritance trees

Limit inheritance hierarchies to 7± 2 total number of sub-classes of a base class

Associated with increased fault rates

Increases complexity

Prefer polymorphism to extensive type checking

switch(ShapeType s)

{

case Circle:

s.drawCircle();

break;

case Square:

s.drawSquare();

break;

…………

}

59

Opportunity for object orientation for polymorphism

59

Inheritance

Make all data private not protected

Breaks encapsulation if client can access directly protected members.

If derived class really needs base class’s attributes, provide protected access functions instead.

60

Summary of when to use Inheritance?

If multiple classes share common data but not behavior, create a common object that those classes can contain

If multiple classes share common behavior but not data, derive them from a common base that defines the common routines

If multiple classes share common data and behavior, inherit from a common base class that defines the common data and routines

Inherit when you want the base class to control your interface; contain when you want to control your interface.

61

Member functions and Data

Keep the number of routines in a class to as small as possible

Disallow implicitly generated member function and operators you don’t want

Do it by declaring function or operator as private

Minimize the number of different routines called by a class (fan-out)

Minimize the indirect routine calls to other classes

Minimize the extent to which a class collaborates with other classes

Minimize number of kinds of objects instantiated

Number of different direct routine calls on instantiated objects

Number of routine calls on objects returned by other instantiated objects

62