You are on page 1of 8

Object Oriented Concepts

1. Introduction

Improvement of programmer productivity has been a primary preoccupation of the software industry since
the early days of computers. Hence it is no surprise that it continues to be a dominant theme even today.
However, it should be noted that concerns arising out of this preoccupation have changed with times. As
software engineering and software technology evolved, the concerns have changed from productivity
during software development to reliability of software. Hence the emphasis on extensibility and reusability
of software modules.
Its perceived benefits are:

• reduction in the effort needed to ensure reliability of software, and


• improved productivities of the software development process

Software being inherently complex, the time tested technique of decomposition also known as "DIVIDE
and CONQUER" has been applied from the early days of software development. Two types of
decomposition have been used, namely, algorithmic decomposition, and object-oriented decomposition.
The algorithmic decomposition views software as
Program={Data Structures}+{Operations}
The program is viewed as a series of tasks to be carried out to solve the problem.
The object-oriented decomposition views it as
Object={Data Structures}+{Operations}
Program={Objects}
The program is viewed as a set of objects, which cooperate with each other to solve the problem.
For example, consider a typical banking system. Algorithmic decomposition views it as a series of tasks,
not unlike the following:

• Open an account
• Deposit money
• Withdraw money
• Transfer money between accounts
• Close an account
• ...etc...

The object-oriented decomposition views it as a set of objects, like the following:

• Account object
o account number (data)
o current balance (data)
o get account number (operation)
o update balance (operation)
• Account holder object
o name (data)
o address (data)
o deposit money (operation)
o withdraw money (operation)
• ...etc...

2. How object oriented decomposition helps software productivity

• Data and operations are packaged together into objects. This facilitates independent and parallel
development of code.
• Because of packaging most updates are localized. This makes it easier to maintain OO systems.
• It allows reuse and extension of behavior.
• Permits iterative development of large systems
Basically, these gains arise from the dominant themes in the OO paradigm.
They are
Data Abstraction: This provides a means by which a designer or programmer can focus on the essential
features of her data. It avoids unnecessary attention being paid to implementation of data.

Encapsulation: This helps in controlling the visibility of internal details of the objects. It improves security
and integrity of data

Hierarchy: It is the basic means to provide extensibility of software modules. and helps in increasing the
reuse of modules.

Polymorphism: It is the means by which an operation behaves differently in different contexts.

These themes are discussed further below against the backdrop of significant periods in the history of
software engineering methodologies.

3. Historical Perspective

After early experience in software development, the software field hoped that structured programming
ideas would provide solutions to its problems. Structured programming is a style of programming usually
associated with languages such as C, Fortran, Pascal and so on. Using structured programming
techniques, a problem is often solved using a divide and conquer approach. An initially large problem is
broken into several smaller sub-problems. Each of these is then progressively broken into even smaller
sub-problems, until the level of difficulty is considered to be manageable. At the lowest level, a solution is
implemented in terms of data structures and procedures. This approach is often used with imperative
programming languages that are not object-oriented languages, i.e. the data structures and procedures
are not implemented as classes. It was looked upon as a technique to make programs easier to
understand, modify, and extend. It was felt that use of the most appropriate control structures and data
structures would make a program easy to understand. It was realised that branching (use of goto's)
makes a program unstructured. It was felt that a program should be modular in nature.

The language PL/I was designed around this time. It is a language rich in data structures and control
structures and promotes modularity. However, ideas of structured programming were devoid of a
methodology. Given a program one could apply the definition of structuredness and say whether it was a
structured program or not. But one did not know how to design a structured program. Similarly, guidelines
for developing good modular structure for a program were conspicuously absent. In the absence of a
methodology, a novice could obtain absurd results starting from a problem specification. For example, the
rule that each module should be about 50 lines of code can be used to decide that each segment of 50
lines in a program should become a module.

Around this time it was also felt that having to use a set of predefined data types of the language was
very constraining, and hence prone to design errors/program bugs. So a methodology for program design
was necessary. It should

• make the task of program design simple and systematic.


• provide effective means to control complexity of program design
• provide easy means to help a user design his data

The PASCAL language was designed with a rich control structure, and the means to support user defined
data. The designer of PASCAL, Niklaus Wirth, also popularised the methodology of stepwise refinement. It
can be summarised as follows:

1. Write a clear statement of the problem in simple English. Avoid going to great depth. Also focus on
what is to be done, not on how it is to be done.
2. Identify the fundamental data structures involved in the problem. This data belongs to the problem
domain.
3. Identify the fundamental operations which, when performed on the data defined in the above step,
would implement the problem specification. These operations are also domain specific.
4. Design the data identified in step 2 above.
5. Design the operations identified in step 3 above. If any of these operations are composed of other
operations apply steps 1-4 to each such operation.

Application of this methodology in a recursive manner leads to a hierarchical program structure. An


operation being defined becomes a 'problem' to be solved at a lower level leading to the identification of
its own data and sub-operations. When a clear and unambiguous statement of the problem is written in
simple English in the above stated manner

• the data gets identified in the abstract form. Only the features of the problem get highlighted.
Other features are suppressed.
• similarly, the essential features of an operation get highlighted
• such data and operations are said to be 'domain-specific'. They are directly meaningful in the
problem domain
• use of domain-specific data and operations simplifies program design. It is more natural than use
of data or operations which have more or less generality than needed. It is also less prone to
design or programming errors.

PASCAL permitted the programmer to define her own data types. These could be
Simple data, viz. enumerated data types.
Structured data, viz. array and record types
Operations on user defined data were coded as procedures and functions. Thus, a user could define the
set of values a data item could take, and could also define how the values were to be manipulated. The
point to be noted here is that permitting a user to define her own data permits her to use most
appropriate data for a problem. For example, an inventory control program could start like this:
type
code = {issue, receipt}
var
trans_code : code;

begin
...
if trans_code = issue then ...
Advantage of this is that programming is now more natural, and hence less prone to errors. PASCAL was
also the first widely used language to emphasize the importance of compile-time validation of a program.
It implies the following:

• Syntax errors should be detected by a compiler. Most compilers do this.


• Violations of language semantics should also be detected by a compiler.
• The semantic checks should also apply to user-defined data.

Thus, invalid use of data should be detected by the compiler. This will eliminate the debugging effort
which would otherwise be required to detect and correct the error. PASCAL does not fully succeed in
implementing compile-time validation. However, stressing its importance is one of its achievements.
PASCAL lacks features to define legal operations on user defined data and to ensure that only such
operations are used on the data. This endangers data consistency. For example:
type
complex_conjugate = record
real1 : real;
imag1 : real;
real2 : real;
imag2 : real;
end;

begin
...
real1 := real1+3; {this violates the idea of complex conjugates}
The user defined data is like any other data and hence its components can be used in any manner
consistent with the type of the components. Hence complex conjugates can only be used in some specific
manner, but this is not known to the compiler. It will allow its component real1 to be used as a real
variable.

SIMULA was the first language, which introduced the concept of classes. Infact, it is the first language
which introduced many of the object oriented concepts, which are taken for granted today. A class in
SIMULA is a linguistic unit which contains:

• Definition of the legal values that data of the class can assume.
• Definition of the operations that can be performed on the data.

A user can create variables of a class in her program, and can use the operations defined in the class on
these variables. This way the compiler knows what operations are legal on the data. Attempts to use any
other operations will lead to compile-time errors. However, it did not provide encapsulation. Encapsulation
implies 'sealing' of the internal details of data and operations. Use of encapsulation in the class promotes
information hiding. Only those data and operations, which are explicitly declared as visible to the outside
world, will be visible and the rest will be hidden. Encapsulation implies compile-time validation. This would
ensure that a program cannot perform any invalid operation on the data. Thus, illegal access to the
imaginary part of a complex number can be prevented. This takes compile-time validation of a program
one step further. (At this point you are encouraged to visit these links.

Data abstraction coupled with encapsulation provides considerable advantages in the presence of
modularity.
Consider a program consisting of two modules A and B. We can make the following observations:

• Module B defines its own data.


• The data of module B can only be manipulated by its operations, also defined in module B.
• Hence, module A cannot access the data of module B directly.
• The responsibility for correct manipulation of the data now rests only with module B.
• Chnages made in module B do not affect module A.
• This simplifies debugging.

Now we are in a position to clarify the expressions:


Object={Data structures}+{Operations}
Program={Objects}

• An object is a collection of data items and operations that manipulate data items.
• A object oriented program is a collection of objects which interact with each other.

Each object is an instance of a class. A class defines a 'data type'. Each object is a variable of a 'data
type'. Thus a class is a template and objects are its 'copies'

• The data structures are declared in the class. The operations are also defined in the class. Each
operation is called a method.
• Each object of the class contains a copy of the data structures declared in the class. These are
called instance variables of the object.
• The operations in all objects of a class share the code of the class methods. Thus a single copy of
the code exists in the program.

In most present-day object oriented systems, the execution of an object oriented program is 'single
threaded', i.e. only one object is active at a time. The program consists of one 'main' object which is
active when the program is initiated.

4. Abstraction

Abstraction provides a well-defined conceptual boundary relative to the perspective of the viewer. When
we define abstract data, we identify their essential characteristics. All other characteristics are
unimportant. There are different types of abstraction:

• Entity abstraction: The object presents a useful model of an entity in the problem-domain
• Action abstraction: The object provides a generalised set of operations, all of which perform the
same kind of function.
• Virtual machine abstraction: The object groups together operations that are all used by some
superior level of control
• Coincidental abstraction: The object packages operations that have no relation to each other.

Entity abstraction is considered to be the best form of abstraction as it groups together the data and
operations concerning an entity. For example, an object called salaried_employee could contain operations
like compute_income_tax, compute_pf, etc. Thus information about an entity is localized. One often faces
the question as to how to identify useful objects from a problem specification. The answer is look for
nouns in the specification. They represent 'things' or entities. This leads to entity abstraction.

5. Encapsulation

While abstraction helps one to focus on the essential characteristics of an object, encapsulation enables
one to expose only those details that are necessary to effectively use the object. This is achieved through
information hiding and "need to know" principle. One could declare some of the variables and methods of
the object as private and the rest public. Only public variables and methods will be accessible by other
objects. By carefully selecting what is available to the outside world, the developer can prevent illegal use
of objects. For example, consider a class called Person with an operation like 'compute_income_tax'.
Details of a person's income are not essential to a viewer of this class. Only the ability to compute the
income-tax for each object is essential. Hence the data members of the class can be declared private,
while 'compute_income_tax' can be public.

6. Hierarchy

Hierarchy is a ranking or ordering of abstractions. The important hierarchies in an OO system are:

• The class structure hierarchy


• The object structure hierarchy

A class structure hierarchy is used for sharing of behaviour and sharing of code between different classes
of entities which have some features in common. This is achieved through inheritance. It is called the 'is a'
hierarchy. Features that are common to many classes are migrated to a common class, called base-class,
(or super-class, or parent-class). Other classes may add, modify, or even hide some of these features.
These are called derived-classes, (or sub-classes, or child-classes). For example, vehicle can be a base-
class and two-wheeler, three-wheeler, and four-wheeler can be derived classes. There is also a possibility
of inheriting from more than one class. This is called multiple inheritance. For example, a two-in-one
inherits the features of a radio and a tape-recorder. However, it can raise the following complications:

• Possibility of name clashes


• Repeated inheritance from two peer super-classes

The object structure hierarchy is also called 'part of' hierarchy. It is implemented through aggregation,
that is one object becomes a part of another object. Aggregation permits grouping of logically related
structures. It is not unique to object oriented systems. For example, in C a structure can be used to group
logically related data elements and structures. In OO context, a vehicle consists of many parts like engine,
wheels, chassis, etc. Hence it can be represented as an aggregation of many parts.

7. Polymorphism

It is a concept wherein a name may denote instances of different classes as long as they are related by
some common super class. Any such name is thus able to respond to some common set of operations in
different ways. For example, let us say that we have declared a class called polygon with a function called
draw(). We have derived three classes, rectangle, triangle, pentagon, each with its own redefinition of the
draw() function. The version of the draw function to be used during runtime is decided by the object
through which it is called. This is polymorphism. It assists in adopting a unified design approach.

8. Modularity

Modularity creates a number of well-defined, documented boundaries within a system. A module typically
clusters logically related abstractions. This is invaluable in understanding a system.

• Each module can be compiled separately, but has connections with other modules.
• Connections between modules are the assumptions which modules make about each other.

Ideally, a module should be a single syntactic construct in the programming language.

9. Meyer's Criteria

Bertrand Meyer suggests five criteria for evaluating a design method's ability to achieve modularity and
relates these to object oriented design:

• Decomposability: Ability to decompose a large problem into subproblems.


• Composability: Degree to which modules once designed and built can be reused to create other
systems.
• Understandability: Ease of understanding the program components by themselves, i.e. without
refering to other components.
• Continuity: Ability to make incremental changes.
• Protection: A characteristic that reduces the propagation of side effects of an error in one module.

Based on the foregoing criteria, Meyer suggests five rules to be followed to ensure modularity:

• Direct mapping: Modular structure of the software system should be compatible with modular
structure devised in the process of modeling the problem domain
• Few interfaces: Minimum number of interfaces between modules.
• Small interfaces: Minimum amount of information should move across an interface.
• Explicit interfaces: Interfaces should be explicit. Communication through global variables violates
this criterion.
• Information hiding: Information concerning implementation is hidden from the rest of the program.

Based on the above rules and criteria, the following five design principles follow:

• Linguistic modular units principle: Modules must correspond to syntactic units in the language
used.
• Self-documentation principle: All information about a module should be part of the module itself.
• Uniform access principle: All services offered by a module should be available through a uniform
notation
• Open-closed principle: Modules should be both open and closed. That is, it should be possible to
extend a module, while it is in use.
• Single choice principle: Whenever a software system must support a set of alternatives, one and
only one module in the system should know their exhaustive list.

A class in an OO language provides a linguistic modular unit. A class provides explicit interfaces and
information hiding. This is what sets OO languages apart from early languages like PASCAL and SIMULA.

10. Characteristics of an object

From the perspective of human cognition, an object is one of the following:

• A tangible and/or visible thing.


• Something that may be apprehended intellectually.
• Something towards which thought or action is directed.

Some objects may have clear physical identities (e.g. machine), while some others may be intangible with
crisp conceptual boundaries (e.g. a chemical process). However, the following statement is true for all
objects:
An object has state, behavior, and identity.
An object's behavior is governed by its state. For example, a two-in-one cannot operate as a radio, when
it is in tape-recorder mode. An operation is a service that an object offers to the rest of the system. There
are five kinds of service:

• Modifier: The operation alters the state of the object.


• Selector: The operation accesses the state of an object but does not alter it.
• Iterator: The operation accesses parts of an object in some order.
• Constructor: The operation creates an object and initializes its state.
• Destructor: The operation destroys the object

There are three categories of objects:

• Actor: The object acts upon other objects but is never acted upon.
• Server: The object is always acted upon by other objects.
• Agent: The object acts on other objects and is also acted upon by others.

There are three types of visibility in to a class.

• Public: The feature that is declared public is accessible to the class itself and all its clients.
• Protected: The feature that is declared protected is accessible to the class itself and all its derived
classes and friends

Private: The feature that is declared private is accessible only to the class itself and its friends.

11. Extensibility

The notions of abstraction and encapsulation provide us with features of understandability, continuity, and
protection. As we said in the beginning, one of the goals of OO paradigm is 'extensibility'. It can be done
in two ways: extension by scaling and semantic extension. Consider a banking application which supports
two 'banking stations'. What changes are required to support additional stations?

• Let us say the application contains a class called BSTATION.


• Each banking station is an instance of this class.
• To incorporate the extension
o We create another instance of BSTATION. This instance will share the code for the methods
with other instances, but will have its own copies of the data.
o Use of the new station is integrated in the software, i.e. provision is made to direct some
workload at the new station.

This is extension by scaling. It is made simple by the notion of a class. We can achieve scaling by merely
declaring another variable of a class.
Semantic extension may involve
Changing the behavior of existing entities in an application.
Defining new kinds of behavior for an entity.
For example,
We may want to compute the average age of students in years, months and days.
We may want to compute the average marks of students.
Let us say these requirements necessitate changes to the entity 'Persons'. The classical process is to
declare that the entity is under maintenance. This implies:
• Applications using 'Persons' must be held in abeyance. They cannot be used until the maintenance
is complete.
• 'Persons' must then be modified. It must then be extensively tested.
• If necessary, each application using 'Persons' should be retested.
• Now existing applications using 'Persons' can be resumed.
• New applications using 'Persons' can be developed, tested, etc.

Thus, this form of maintenance for extension is obtrusive. It interrupts the running applications. Avoiding
obtrusion leads to different versions of software. Semantic extension using object oriented methodology
does not suffer from this problem. Applications using an entity are not affected by the extension and can
continue to run while the entity is being extended. Such applications need not be retested nor revalidated.
This is achieved through the notion of inheritance.

12. Conclusions

Thus object-oriented approach has many advantages over the structured methodology. There are many
languages which support object-oriented programming. Some of the popular ones are, Smalltalk, Eiffel,
Ada, C++, Java. The choice of the language will usually be based on business requirements. Object-
oriented approach itself is most suitable in business areas which are

• Rapidly changing
• Require fast response to changes
• Complex in requirements or implementation
• Repeated across company with variations
• Having long-life applications that must evolve

You might also like