High Quality Routines
Terminology Review
Abstract data type (ADT) definition of the type, together with the operations defined on the type (ignoring unimportant details – typically implementation).
Abstraction: reasoning about the essential properties of an object, ignoring unimportant details.
Implementation: an object build to satisfy a specification
Information hiding: embedding the details of a program element inside the element in such a way that when it is applied, its inner details do not need to be known.
Inheritance: the mechanism by which we build new classes on old ones.
Interface: the way in which an object interacts with its environment
Specification: a detailed description of the essential properties of an object
Why Create High-Quality Routines?
- Reduce complexity.
- Hides information so you don’t need to think about it after the routine is written (compartmentalize tasks).
- Reduces code size and improves maintainability.
- Create useful abstractions.
- Puts code into a well named routine which makes it easier to understand.
- Avoids duplicate code.
- Hide sequences of operations.
- Hide pointer operations.
- Improve portability.
- Simplify Boolean operations.
- Optimizes code.
Abstracting Data
- Data types/algorithms organized into modules.
- Module contains data structure + operations.
- Module exports (makes public).
- A type (in an object oriented language this is the class itself).
- Methods that operate on instances of this type.
- User of the module can declare variables of this type, and manipulate them by calling the ADT’s operations.
During Implementation (Code)
- Specification: subroutine header + pre/post conditions.
- Implementation: local variables + body of subroutine.
Data Types
- Specification: definition of data type + operations defined on that type.
- Implementation (in C): a .h header file containing type and function declarations together with a .c file in which they are implemented.
ADT Module Conventions
- ADT lifecycle: declare -> create -> use -> destroy
- others: read, write, isEqual, isEmpty, etc.
- common to use names such as typeRead, typeWrite, etc. in languages where namespace collisions are an issue.
Abstraction Levels
- Each level strives to specify enough detail to permit problem solving and reasoning at that level, but ignores unimportant considerations.
-
These issues are deferred to the more refined levels below.
- Abstract level: relation between data and operations needed.
- Data Structures level: specify enough detail to analyze the behaviour or our operations and make appropriate decisions as dictated by our problem (e.g. linked list vs. linear list depending on expected use)
- Implementation level: high-level implementation detail (e.g. linked list using pointers/ references or indirection via indices in an array).
- Application level: low-level implementation detail (e.g. variable names and special requirements/limitations imposed by the application).
Inheretence
- The objective with inheritance is to make code reuse possible on a grand scale.
- ie. if we define a Stack, we only need to code the part that is different from a List.
- Inheritance has an is-a relationship; suppose class D is derived from class C:
- The implication is that derived class D is-a C.
- Whatever an object of class C can do, so should an object of class D.
- Intended for augmentation, should not be restrictive.
- Principle of Substitution: designed to preserve the relation that a derived class is-a class of the same kind as all of its parents.