You are on page 1of 15

CS F213 Object Oriented Programming: Class and Lab Notes

Ramprasad S Joshi

August 2023
Abstract

We focus on practice sessions and examples or experiments that consolidate the discussions dyring lectures.
Chapter 1

Introduction and Preliminaries

Object oriented programming is not about classes and methods, or about some condensed jargon like encapsulation and
code reusability. Computational models of real-life interaction follow conceptualization of the entities involved in that
interactions, the various modes of that interaction, and the relationships, constraints and interdependence amongst the
entities that shape up the interaction patterns. This conceptualization is best done in a functional object-oriented design.
Our textbook says about itself [Blaha and Rumbaugh, 2004, pp.xv–xvi, Preface]:
Our emphasis differs from that of some in the object-oriented programming community but is in accord with the information
modeling and design methodology communities. We emphasize object-oriented constructs as models of real things, rather than as
techniques for programming. We elevate interobject relationships to the same semantic level as classes, rather than hiding them
as pointers inside objects. We place somewhat less emphasis on inheritance and methods. We downplay fine details of inheritance
mechanisms. We come down strongly in favor of typing, classes, modeling, and advance planning. We also show how to apply
object-oriented concepts to state machines.
...
There are many books on the market that cover object-oriented technology. This book differs from most in that it teaches
how to think about object-oriented modeling, rather than just presenting the mechanics of a programming language or modeling
notation.
Many of the available object-oriented books are about programming issues, often from the point of view of a single language.
Some of these books do discuss design issues, but they are still mainly about programming. Few books focus on object-oriented
analysis or design. We show that object-oriented concepts can and should be applied throughout the entire software life cycle.
In addition there are a number of books that present the concepts of the UML. This book is different than most in that it
not only explains the concepts, but it also explains their fundamental purpose and shows how to use them to build software. We
do not explain every concept and nuance, but we do strive to explain the core of UML–enough to help you learn how to use the
UML to build better software.
...
We have carried forward the first edition’s focus on “the three models” because we believe such an emphasis is helpful
for teaching and learning OO modeling. However, we dropped the functional model, because it was not as useful as we had
expected. In its place, we added the interaction model to incorporate use cases and sequence diagrams and to give a more holistic
understanding of behavior among several objects.

This tells us several things:

1. The textbook focuses on OO modeling of real things (including real systems).


2. Languages and syntax are considered secondary, instrumental.
3. Software system level design tools and techniques are emphasized.
4. Modeling interaction among system components explicitly is emphasized.
Note that the functional model that the authors are referring to from the first edition is not about the functional program-
ming paradigm but about modeling real systems by functions of and relationships amongst entities for object-oriented
design.

Our Approach We will indeed follow the textbook in the focus and emphasis described above. However, the book itself
was written for advanced undergraduates and graduates and professionals. Therefore, we will begin somewhat leisurely,
with top-down modular design, and pose real, practical questions for modeling real systems before introducing the tools,
techniques and programming language constructs required to model and implement them computationally. These tools,
techniques and constructs will appear to be necessary and enabling after we struggle without planning with the usual
programming toolchains and habits that we often resort to.

1
1.1 Some Slang for Ourselves
We will memorise some colloquial terminology that will have temporary meanings in our labs and classes this semester.
From time to time, we will align these terms with the more “standard” terms in use in textbooks and tech communities.
This section will grow as the semester proceeds.

1.1.1 Separations
We seek the following separations (among many others, of course) with specific purposes:
What How
Function Implementation
Behaviour State and Methods
Privacy, Integrity, Security Interfaces and Protocols
Events and Synchronization Message Passing and Real-time exceptions and interrupts

1.2 The First Separation Structure: Modularity


We will write a multi-module program for the first lab (Tuesday 22 August 2023).

The Task
1. The top level: Build an application that offers a generic storage type Dictionary equipped with a retrieval mechanism
for arbitrary amounts of numbers.
2. Desirable design goals: Offer the end user a choice of data invariants. The invariants may be
• The stored data are always sorted.
• The data may be sorted on one of the pre-fixed functions on the data. e.g., Sorting them on squares, on absolute
values, or on a given polynomial value. Thus, [-2,-1,0,1,2] is sorted on the identity function f (x) = x, but on
squares f (x) = x2 or absolute values f (x) = |x| they are sorted as [0,-1,1,-2,2]. Note that this is a stable sort.
On the polynomial f (x) = ax2 + bx + c, if b2 − 4ac = 0 and b > 0 then again the sort will be [0,-1,1,-2,2].
• In general, then provide a sorting function that takes a key function and the dictionary as parameters and sorts
the dictionary elements on the key function values on each of them.

1.2.1 Skeletal Code


There will be two modules (at least): that means two .c (source) files and one .h (header).
Module 1: The main module.
// main.c
#include "dict.h"
#include<stdlib.h>
// ... anything needed ...
// ...
int main(int argc, char *argv[]) {
Dict d1;
d1=ConsDict(argc-1);
// -- Make a dictionary of as many elements
// as passed on the command line
int i;
for (i=1; i<=argc; i++) {
InsertDict(d1,atoi(argv[i]));
}
DisplayDict(d1);
SortDict(d1);
DisplayDict(d1);
}

2
Module 2: The dict module
//dict.c
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<error.h>
typedef int *Dict;
Dict ConsDict(int size) {
int *p=(int*)malloc((size+2)*sizeof(int));
p[0] = 0; p[1] = size;
return p;
}
void SortDict(Dict d) {
BubbleSort(d+2,d[0]);
// Sort d[0]=actual count elements in it
}
void InsertDict(Dict d, int i) {
if(d[0]==d[1]) error(-1,0,"Dictionally full!");
d[d[0]+2]=i;
d[0]+=1;
}
void DisplayDict(Dict d) {
int i;
printf("Displaying dictionary with %d elements, size %d: ",d[0],d[1]);
for(i=2; i<d[0]+2; i++) {
printf("Element%02d=%d ",i-1,d[i]);
}
printf("\n");
}
The header file is not much :
// dict.h
typedef void *Dict;
extern Dict ConsDict(int);
extern void SortDict(Dict);
extern void DisplayDict(Dict);
extern void InsertDict(Dict,int);
Copy these code snippets into the suggested files, provide the usual bubblesort in dict.c, and compile by
$ gcc main.c dict.c
and run (the program, not from the lab) as:
$ ./a.out 5 4 2 1 3
Then you should be able to see
Displaying dictionary with 5 elements, size 5: Element01=5 Element02=4 Element03=2 Element04=1
Element05=3
Displaying dictionary with 5 elements, size 5: Element01=1 Element02=2 Element03=3 Element04=4
Element05=5
Provision for the compare functions will be made and explained tomorrow in the lab.

1.2.2 Lessons Drawn


We witnessed and observed
1. Separation between specifications (function) and implementation.
2. Various ways of accomplishing the same tasks.
3. Comparison on modularity and object orientation of those various ways.

3
4. Separation between the application (client) view of a data structure (dictionary as seen in the main module via
dict.h) and
5. How and why C is not smoothly adaptable to object oriented design.

1.3 A Java Implementation


We go via the Class Model [Blaha and Rumbaugh, 2004, 2.3.1]: The class model describes the structure of objects in a
system – their identity, their relationships to other objects, their attributes, and their operations... Objects are the units
into which we divide the world, the molecules of our models.
In our case: We describe the structure of a dictionary. Its identity (for our application) is “a collection of elements”
– i.e. a collection of numbers. Its attributes are size and occupancy count. Operations are inserting, deleting, replacing,
finding elements, and sorting (the whole) on a key function.
Class diagrams express the class model. Generalization lets classes share structure and behavior, and associations
relate the classes. Classes define the attribute values carried by each object and the operations that each object performs
or undergoes.

The codes are uploaded on quanta-aws.

1.4 Lab Session 29 August 2023


Using the two Java programs MyDictionary and DictionaryApp as seeds, develop the full dictionary data structure and a
demonstrative application on it. By a full dictionary data structure, we mean the capabilities of easy and efficient creation,
search and retrieval, upkeep and updation. More versatility, not necessary but desirable, is in the trade-offs in the design:
for example, if search and retrieval are most important and more often needed than creation and updation, then keeping
it sorted internally is beneficial. But if all the operations are equally frequent, then internally a priority queue, or some
balanced tree structure is desirable.
All the foregoing wish list is not for tomorrow, but it must be in your mind when you are doing the initial design as
well. Do not make a rigid design that will require a complete overhaul or replacement as development advances to more
desirable features. Think reusability from the beginning.
There may be a quiz on the programs developed later. Later doesn’t necessarily mean tomorrow. The quiz may also be
on future development starting from tomorrow. Such a quiz will first determine your design choices (and, if your answers
to questions on such choices are not consistent with your actual design and development, you lose marks – that’s the
evaluation). In the remaining sections, through various types of questions including but not limited to MCQs, you will be
asked to justify or criticise your own choices, and to suggest desirable modifications. For these sections, the answers will
be evaluated on two axes of consistency: consistency with your actual design and development, and consistency with the
established common principles described in the textbook and reference books. Such quizzes will test your understanding,
the lessons learnt (not just read), and will reinforce it.
This quiz is almost impossible to be conducted tomorrow. But you should keep in mind this method of evaluation
throughout your design development plans and effort, beginning now. That means, keep the following points in consider-
ation throughout.

4
1. Make conscious choices and document them.
2. Documenting design choices includes recording the reasons for rejecting the alternatives also, for all the rejected
alternatives.
3. Do not be rigid, be ready to change the choices and code later, albeit with due reasoning and documentation.
4. Design changes should be tracked via version control. Next week we will introduce version control, and the tools
and techniques and systems to maintain it. Do not hide or forget the mistakes, in fact, remember the lessons learnt
well.

1.5 Setting up Your Development Environment


I am going to use the Spring Framework. More on the choices available to you will be found in Appendix B below.

5
Chapter 2

The Class Model

Let us start with Blaha and Rumbaugh [2004, Chapter 3]: the Class Model. However, before we embark on the actual
modeling exercises in this particular manner, let us have a look at modeling as a part in a design cycle, a la Blaha and
Rumbaugh [2004, Chapter 2].

1. All models are false, some are useful (an oft-repeated quote in Physics attributed to all and sundry).
2. Typically, in sciences, modeling is used in order to understand and describe something after the fact of its happening
or coming into being. Like, forensics. Usually, a pattern is surmised, detected and modeled, so as to predict and
test it further.
3. This is theory-building.
4. For our purposes for this course, a model is an abstraction of something for the purpose of understanding it before
building it.

2.1 Modeling and Abstraction


We have various kinds of models, the kind depending each time on the purpose more than on the real-world object
or idea that is modeled. Thus, physical models, such as the ones built by Indian engineers of the first IES batch in
1950s before building the big dams like the Bhakra-Nangal, are built to study the characteristics of a similar system, or
prototype, usually more complex or built to a widely different scale. See https://www.engineeringcivil.com/similitude-for-
physical-models.html. Then there are 3-D models of buildings drafted by architects and draftsworkers using pencil and
paper or software, or more recently, even 3-D printing, more for visualisation and advertisement for potential customers.
The software tools needed to design and render/display such models will be object oriented, almost of necessity. There
are more such visualization models that simulate (or help visualize) not physical but graphical characteristics of the
modeled objects or systems: the look and feel. This is what was promised in the idea of “WYSIWYG” (What You
See Is What You Get) graphical user interfaces. Thus, OO modeling and programming became the dominant and
natural mode of software development with the advent of GUIs. If one wants to have a glimpse of what OO methodology
meant for less visualizable interfaces, e.g. the On Line Transaction Processing OLTP systems, one may read
https://www.developer.com/design/objects-and-client-server-connections/.
Abstraction is a condensed analytical description of certain selected aspects of something complex. The selected
aspects are chosen to be essential to the purpose of modeling that entity or idea. As the legendary sculptor Michelangelo
Buonarroti said:

this often requires choosing the superfluous so that the essence is just uncovered.

6
2.1.1 All Models are False, Some are Useful
Blaha and Rumbaugh [2004, p.16] say:
All abstractions are incomplete and inaccurate. Reality is a seamless web. Anything we say about it, any description of it, is
an abridgement. All human words and language are abstractions–incomplete descriptions of the real world. This does not destroy
their usefulness. The purpose of an abstraction is to limit the universe so we can understand. In building models, therefore, you
must not search for absolute truth but for adequacy for some purpose. There is no single “correct” model of a situation, only
adequate and inadequate ones.
A good model captures the crucial aspects of a problem and omits the others. Most computer languages, for example, are
poor vehicles for modeling algorithms because they force the specification of implementation details that are irrelevant to the
algorithm. A model that contains extraneous detail unnecessarily limits your choice of design decisions and diverts attention from
the real issues.

Applying it to our humble Dictionary We want a data structure that can store unbounded (but reasonable) amounts
of all perceivable kinds of data and allows retrieving them efficiently.

What is essential in a Dictionary data structure that allows for much flexibility in its storage and retrieval, with
seamless and easy adaptation to any application without requiring an overhaul or construction of several types?
But this question may be premature for many. Before that, especially those who have not yet seen so many different data
types, of complex and varied layouts and formats and sizes, would like to ask:

How many element types do we need to examine and model before we can model and design an aggregate of those
elements, the desired Dictionary data structure?
Let us summarise.
• If we make storage most efficient, i.e., we just store a new element in the next available slot, then retrieval may not
be efficient. For each query or update, we may need to just search blindly through the aggregate, worst case O(n)
time when n is the number of elements stored. Imagine if our Library just dumped books onto shelves, without call
numbers and ordering and guides pasted on the shelves–what a nightmare would it be to borrow a book?
• If we want to make retrieval most efficient, we can keep an index on the stored elements: Given an element e, we
use a function Index(k) that gives (in some way) “direct access” to the element that has key k, without the need
for any comparison and search. How can we do this without requiring a search on the indices k themselves? This
question we need not solve algorithmically, at least for now. Reserve that for the Data Structures and Algorithms
course. We will simply look for a data structure that gives us such a “direct access”. But does that data structure
be the Dictionary that we are trying to model and build? Did this deteriorate into some circular modeling and
design exercise?

Actually there is no need to despair so. We look for some indexing or mapping scheme that finds the “address” of an
element (or some way to access it “directly”) given its key. i.e. We use the same Index(k) function to find a suitable
place for a new element (k, v), and to retrieve it once placed. Then both the problems above appear to be solved at once.
More importantly, we need not solve the problems by our own clever tricks nor do we need to prove the correctness and
efficiency of our solutions. That is, while designing our Dictionary abstract data structure, we need not even design for
the desired efficiency parameters.

We design the Dictionary to be adaptable to any efficiency goals, subject to provisioning


of the appropriate efficient methods.

7
Iterative Design Ideally, we would set out to design an abstract Dictionary only after extensive experience with
many concrete implementations of the as yet vague, undefined abstrat idea with varying efficiency goals, using the insights
distilled from that experience. Indeed, that is how abstraction actually happens and works. But for several reasons,
including the lack of any serious programming experience for most of the class, we will simply draw upon the received
collective wisdom. Using a telescope, or sending a Chandrayan, we obviate the need to die to see the heavens.

Three Models Blaha and Rumbaugh [2004, Chapter 2] describe three models:
The class model describes the static structure of a system in terms of classes and relationships. The state model describes the
control structure of a system in terms of events and states. The interaction model describes how individual objects collaborate to
achieve the behavior of the system as a whole. Different problems place different emphasis on the three kinds of models.

We embark on building a Class Model of our Dictionary.

The Class Model Blaha and Rumbaugh [2004, p.21] say:


• A class model captures the static structure of a system by characterizing the objects in the system, the relationships
between the objects, and the attributes and operations for each class of objects.
• Blaha and Rumbaugh [2004] emphasize building a system around objects rather than around functionality, because
an object-oriented system more closely corresponds to the real world and is consequently more resilient with respect
to change.
• Class models provide an intuitive graphic representation of a system and are valuable for communicating with
customers.

2.2 The Dictionary Class


This is an abstract data structure that provides for fields that maintain an aggregate and various metadadta on the aggre-
gate and its elements. The methods it provides are Insert, Modify, Delete, Search, Replace, FindRank, AssignRank.
The underlying element that makes an aggregate, and the nature of keys used to rank and order elements are details of
implementation, not of the abstract design. The design provides for arbitrary element and key types with just one proviso:
that the keys must be comparable in a total order. Similarly, efficiency considerations and trade-offs among them are
relegated to the implementation, not committing to any specific recommendations in the abstract design.
Note, we are not talking of an abstract class in Java yet. We will come to that, when it
is needed. Not now.
The following is loosely borrowed and modified from the description of the utility class Dictionary in Java (java.util).

The Design
• Our Dictionary class a class that represents a collection of key-value pairs, where keys are
unique and are used to access the values.
• It provides the basic operations for accessing the key-value pairs stored in the collection,
which can be implemented by several underlying concrete storage structures. In the first
version, we continue our use of arrays.
• A Dictionary object needs the following attributes (fields):
records : Record[] An array of Records (Record will be another class, we will see soon. It needs to provide
a comparable key.)
size : available size.
length : count of records.
ordering : enum {NONE,ASC,DESC,PRIQASC,PRIQDESC,BST}. (This ordering means: none, ascending, descend-
ing, priority-queue-ascending giving the top element to be always the smallest, priority-queue-descending giving
the top always to be the largest, and binary search tree. These structures we can borrow from some standard
library if available, or leave for the implementer to implement. Each of the methods that modify the collection
in any way must consult this parameter and invoke corresponding ordering algorithm, possibly added as an
additional private method.)

8
• The Dictionary class defines the following methods:

get(int key) : Returns the value associated with the specified key in the dictionary, or null
if the key is not found.
put(Record record) : Inserts a record into the dictionary. If the key provided by the record
already exists, its corresponding record is replaced with the new record, and the old
record is returned. If the key is new, null is returned.
remove(int key) : Removes the record associated with the specified key from the dictionary,
and returns it. If the key is not found, null is returned.
size() : Returns the number of records stored in the dictionary.
isEmpty() : Returns true if the dictionary is empty, and false otherwise.
isFull() : Returns true if the dictionary is full (size==count), and false otherwise.
records() : Returns an enumeration of the records stored in the dictionary.
keys() : Returns an enumeration of the keys stored in the dictionary.

The Record Class Since we want this class to be “generic”, in the sense that we want to allow arbitrary structures to
be stored in this, we have to invoke the Dictionary instantiation from a suitable directory such that the JVM finds the
intended Record class in the classpath first.

Sample Record class It has two members, key:int and value:double. There is a data invariant to be maintained
as: key = ⌊value⌉ where ⌊.⌉ means the nearest integer as defined next. Thus,

⌊1.2⌉ = 1, ⌊1.6⌉ = 2, ⌊1.5⌉ = 2, ⌊0.5⌉ = 0, ⌊−1.2⌉ = −1, ⌊−1.6⌉ = −2, ⌊−1.5⌉ = −1, ⌊−0.5⌉ = −1.

Note the apparent inconsistency ensuring that no two numbers with a difference equal to 1 map to the same
integer. The constructor to the class and all other methods must at the end restore this data invariant
before returning. The methods of any Record class are: getKey(): int and getValue: double. If more
are provided, that can modify it, then the data invariant must be respected by them.

2.2.1 Tasks for the Lab Session on 5 September


1. Complete the class definitions, for the Dictionary and Record and enum Ordering classes.
2. Implement all of them by populating the required methods, including constructors.

3. For all this, set-up your gitLab (https://gitlab.com/ accounts and fork the https://gitlab.com/cs-f2131/OOP
project. Tune your tools and development environment to your needs and style.
4. More than getting everything completed, making your own development environment and making a complete pro-
totype that builds into one executable and at least shows the methods to be invoked and what they are expected
to do in plain text, if not actually accomplishing it, is the goal for this session. Use the separation of the app main
and the Dictionary type done last time.
5. Record a log of your activities, their success/failure, and lessons drawn/learnt for future, in your gitLab account.

9
Appendices

The Appendices will collect, without any particular order or anchoring in the main text, articles relevant to the course.
These are to be used as reference material.

10
Appendix A

Java

A.1 Why Java?


https://www.developer.com/java/top-java-frameworks/ says at the outset:
Right now, in 2023, Java is the third most popular programming language in the world with more than 9 million Java
developers worldwide (Python and C occupy the top 2 spots respectively). Java’s enduring success can be attributed to a few key
factors:
• It is a platform-independent language (as highlighted by Java’s “write once, run anywhere” motto)
• It follows the object-oriented programming paradigm
• Its syntax is similar to other well-understood languages such as C++.

11
Appendix B

Development Frameworks and IDEs

Read https://www.developer.com/java/top-java-frameworks/ and https://www.geeksforgeeks.org/top-10-most-popular-


java-frameworks-for-web-development/.

12
Bibliography

Michael Blaha and James Rumbaugh. Object-Oriented Modeling and Design with UML. Prentice Hall/Pearson, 2nd
edition, 2004.

13

You might also like