software engineering
DESCRIPTION
Class design. Software Engineering. Class design – ADT. Abstract Data Types : Why use ADT? Hidden implementation details Changes do not affect whole program More informative interfaces Easier to improve performance Programs easier to verify “Self-documenting” programs - PowerPoint PPT PresentationTRANSCRIPT
Software Engineering
Class design
Class design – ADT
Abstract Data Types: Why use ADT?
Hidden implementation details Changes do not affect whole program More informative interfaces Easier to improve performance Programs easier to verify “Self-documenting” programs “Higher level programming”
Class design – ADT
Abstract Data Types:
ADT = abstract (mathematical) model + operations defined on it
Class = ADT + inheritance + polymorphism
Class design – interfaces
Abstraction
Encapsulation
Class design – interfaces
Abstraction: Example of good abstraction (C++):
class Student {public: Student(); Student( FullName name, String address, String studentID ); virtual ~Student();
FullName GetName() const; String GetAddress() const; String GetStudentID() const; ...private: ...};
Class design – interfaces
Abstraction: Example of bad abstraction (C++):
class StudentList: public ListContainer {public: ... void AddStudent(Student student); void RemoveStudent(Student student); ... Student NextListItem(); Student FirstItem(); Student LastItem(); ...private: ...};
Different levels of abstraction
Class design – interfaces
Abstraction: guidelines to build good interfaces Present a consistent level of abstraction
in the class interface – each class should implement one and only one ADT
Heuristic test for inheritance relations: is inheritance being used only for “is a” relationships? (Answer should be YES)
Class design – interfaces
Abstraction: guidelines to build good interfaces
Be sure you understand what abstraction the class is implementing
Class design – interfaces
Abstraction: guidelines to build good interfaces
Provide services in pairs with their opposites – add/remove, activate/deactivate, on/off, ...
Class design – interfaces
Abstraction: guidelines to build good interfaces
Move unrelated information to separate classes – if you have “isolated” data and routines within a class, they should form a separate class
Class design – interfaces
Abstraction: guidelines to build good interfaces Make interfaces programmatic rather
than semantic whenever possible
programmatic = compiler can checksemantic = e.g. “RoutineA must be called before RoutineB”
Class design – interfaces
Abstraction: guidelines to build good interfaces
Beware of “erosion” of the interface´s abstraction under modification
Class design – interfaces
Abstraction: guidelines to build good interfaces
Do not add public members that are inconsistent with the interface abstraction
Class design – interfaces
Abstraction: guidelines to build good interfaces
Abstraction and cohesion come together and are strongly correlated
Class design – interfaces
Encapsulation: guidelines to build good interfaces Minimise accessibility of classes and
members - “private” is better than “protected”, and both are better than “public”
goal is to preserve the integrity of the interface abstraction
Class design – interfaces
Encapsulation: guidelines to build good interfaces Do not expose member data in publicfloat x;float y;float z;
Bad design: data (and their representation) are exposed to external manipulation
float GetX();float GetY();float GetZ();void SetX(float x);void SetY(float y);void SetZ(float z);
Good design: internal data (and how they are represented, and where they are stored, etc.) are protected from external manipulation
Class design – interfaces
Encapsulation: guidelines to build good interfaces
Avoid putting private implementation details into a class interface
Class design – interfaces
Encapsulation: guidelines to build good interfaces
Do not make ANY assumption about the class users
Class design – interfaces
Encapsulation: guidelines to build good interfaces
Avoid “friend classes”
Class design – interfaces
Encapsulation: guidelines to build good interfaces
Do not put a routine into the public interface just because it uses only public routines
Class design – interfaces
Encapsulation: guidelines to build good interfaces
Give priority to read-time convenience over write-time convenience – code is read much more than written. When writing code, make it good to be read, even if it demands more work to be written
Class design – interfaces
Encapsulation: guidelines to build good interfaces Beware of semantic violations of
encapsulationSome examples of semantic violations of encapsulation: Not calling Initialise(), because Operation() calls it Not calling Terminate(), because LastOperation() calls it Not calling Database.Connect(), because Retrieve() calls it Using MAX_ROWS instead of MAX_COLUMNS because you know that
every table has same number of rows and columns
Class design – interfaces
Encapsulation: guidelines to build good interfaces
Beware of tight coupling
Class design & implementation
Containment (“has a”): “has a” should be always implemented
through containment
Sometimes, it may be necessary to implement “has a” through private inheritance. This should be considered bad practice, as it leads to tight coupling and violates encapsulation
Class design & implementation
Containment (“has a”):
Be critical of classes that contain more than about seven data members
SEVEN = heuristic magic number
Class design & implementation
Inheritance (“is a”):general considerations For each member routine, will the routine
be visible to derived classes? Will it have a default implementation? Will the default implementation be overridable?
For each data member, will the data member be visible to derived classes?
Class design & implementation
Inheritance (“is a”):general considerations Implement “is a” through public
inheritance
Be, however, rigorous about implementing through public inheritance strictly “is a” relationships
Class design & implementation
Inheritance (“is a”):general considerations Design and document for inheritance, or
prohibit it
C++: non-virtualJava: finaletc.
Class design & implementation
Inheritance (“is a”):general considerations Liskov substitution principle: all the
routines defined in the base class should mean the same thing when they are used in each of the derived classes
Class design & implementation
Inheritance (“is a”):general considerations
Do not reuse names of non-overridable base-class routines in derived classes
Class design & implementation
Inheritance (“is a”):general considerations
Move common interfaces, data and behaviour as high as possible in the inheritance tree
Class design & implementation
Inheritance (“is a”):general considerations
Be suspicious of classes of which there is only one instance: should it be an object instead of a class?
Class design & implementation
Inheritance (“is a”):general considerations
Be suspicious of classes of which there is only one derived class
Class design & implementation
Inheritance (“is a”):general considerations Be suspicious of classes that override a
routine and do nothing inside the derived routineoperation() ...
operation()// empty body
operation() ...
Class design & implementation
Inheritance (“is a”):general considerations
Avoid deep inheritance trees – usually, more than three levels of inheritance suggest overly complex design
Class design & implementation
Inheritance (“is a”):general considerations
Prefer polymorphism to extensive type checking
Make all data private, not protected
Class design & implementation
Inheritance (“is a”):general considerations Multiple inheritance can be powerful, but
it also can make the program too complex. If possible, avoid it
Inheritance (in general) is very powerful, but should always be used with care, so as not to increase program complexity unnecessarily
Class design & implementation
Member functions and data: Keep the number of routines in a class as
small as possible Disallow implicitly generated member
functions and operators you do not want Minimise the number of different routines
called by a class Minimise indirect routine calls to other
classes – such as rout1.Rout2().Rout3().Rout4()
Class design & implementation
Member functions and data: In general, minimise the extent to which a
class collaborates with other classes – try to minimise:
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
Why classes?
Model real-world objects Model abstractions of real-world
objects Reduce program complexity Isolate complexities Hide implementation details Limit effects of change
Why classes? (cont.)
Streamline parameter passing Facilitate reusable code Plan for a family of programs Package related operations