Object Orientated Thinking

advertisement
Object-Oriented Thinking
Object oriented programming was developed to manage complexity. This is done by
modelling only the essential aspects of a problem. The closer your program models the
problem you are trying to solve, the easier it is to understand the program (and hence write
and maintain it). The term problem domain refers to all the essential information about the
problem.
A well designed object-oriented program will be filled with objects from the problem
domain. At the first level of design you will think about how these objects interact, and what
their state and capabilities are. An objects state is the values it holds. Its capabilities are what
it can be told to do.
Humans create models to manage complexity and to help in understanding the problems to be
solved. A map is an example of a model that can be used to solve the problem of finding your
way from Paisley to Barrhead. To be useful a model should be a simplification. To get from
Paisley to Barrhead you don't need details of individual houses or factories, all that is in the
problem domain is details of the road system. A model must be faithful to those aspects of the
problem domain that are relevant, eg our map should represent distances accurately.
A good object-oriented design is an accurate model of the problem you are trying to solve,
this allows you to examine the relevant details of the problem without confusion.
Classes and Objects
The most important "buzzwords" in object-oriented programming are the class and the object:
A class defines a new type of thing. The class defines the common characteristics of every
object of that new type.
An object is an individual instance of a class. An object is just a thing.
Look around you and you will see things: pen, pencil, paper, table, seat, etc. The pen is an
instance of a more general type of thing, ie a type of implement for writing on paper. The
pencil is also an instance of this general type. The theory behind object-oriented
programming is that for computer programs to accurately model the world, the programs
should reflect the human tendency to think about individual things and types of things. In
Java you do that by creating a class to define a type and creating an object to model a thing.
When you define a class you describe the characteristics and behaviour of objects of that
type. In Java you describe the characteristics with instance variables. These are used to hold
each object's state, eg the state of an Employee object might be defined by (among other
things) their current salary, management level, and performance rating. You define the
behaviour of your class with methods; these contain code to perform an action. An Employee
class might contain methods for adjusting salary, submitting annual reviews, and evaluating
performance objectives.
Methods can manipulate the state of the object by changing the values in instance variables,
or a method could interact with other objects of its own type or with objects of other types.
This interaction among objects is crucial to object-oriented programming.
Designing a good object-oriented program is not unlike forming a good team; you look for
players (or objects, in the case of a program) with different skills to whom you can assign the
various tasks you must accomplish. Those players cooperate with each another to get the job
done.
In a good object-oriented program, you will design objects that represent things in your
problem domain. You will then divide the work of the program among your objects,
assigning responsibilities to objects based on their ability.
Class Relationships
The heart of object-oriented design is establishing relationships among the classes. Classes
interact and relate to each other in various ways.
The simplest interaction is when a method in one class is used to call a method in a second
class, eg the Manager class might have a method that calls the UpdateSalary method on an
object of type Employee. We can then say that the Manager class and the Employee class are
associated. Association among classes simply means they interact.
Some complicated types are composed of other types, eg a car might be composed of wheels,
engine, gearbox, etc. You might model this by creating a Wheel class, an Engine class, and a
Gearbox class. You could then create a Car class, and each car would have four instances of
the Wheel class, and one instance each of the Engine and Gearbox classes. Another way to
view this relationship is to say that the Car class aggregates the Wheel, Engine, and Gearbox
classes. Aggregation is a has-a relationship.
This process of aggregation allows you to build very complex classes from relatively simple
classes. The Java API provides a String class to handle text strings. You might create your
own Address class out of five text strings (address line 1, address line 2, town/city, county,
postcode). You might then create a second class, Employee, which has as one of its members
an instance of Address.
Encapsulation
The idea behind encapsulation is that you want to keep each class discreet and self-contained.
This allows you to change the implementation of one class without affecting any other class.
A class that provides a method that other classes can use is called a server. A class that uses
that method is called a client. The goal of encapsulation is that you can change the details of
how a server does its work without breaking anything in the implementation of the client.
This is accomplished by drawing a line in the sand between the public interface of a class
and its private implementation. The public interface is a contract issued by your class that
says, I promise to be able to do this work. Specifically, a public interface says call this
method with these parameters and I'll do this work and return this value. A client can rely on
a public interface not to change. If the public interface does change, then the client must be
recompiled and perhaps redesigned.
The private implementation, on the other hand, is private to the server. The designer of the
server class is free to change how it does the work promised in the public interface, so long
as it continues to fulfil the terms of its implicit contract: it must take the given parameters, do
the proposed work and return the promised value.
Specialization
Specialization is implemented in Java by declaring that a new class derives from an existing
class. When you do so, the specialized class inherits the characteristics of the more general
class. The specialized class is called a derived class (or subclass), while the more general
class is known as a base class (or superclass).
The specialization relationship is referred to as the is-a relationship. A Car is a Vehicle (Car
would be derived from the base class Vehicle).
Specialization allows you to create a family of objects. These characteristics and behaviours
of the superclass are inherited by all of its subclasses. This allows for a very powerful form of
reuse. Rather than cutting and pasting code from one class to another, the shared variables
and methods are inherited by the subclass class. If you change how a shared behaviour is
implemented, you do not have to update code in every derived type; they inherit the changes.
For example, A Manager is a special type of Employee. The Manager adds new capabilities
(hiring, firing, rewarding, praising) and new state (annual objectives, management level, etc).
The Manager, however, also inherits the characteristics and capabilities common to all
Employees. Thus a Manager has an address, a name, an Employee ID, and Managers can be
given raises, can be laid off, and so on.
Specialization allows you to establish hierarchical relationships among your classes, eg a
Manager can be a specialized type of an Employee, which in turn can be a specialized type of
Person, and so on.
Polymorphism
Polymorphism refers to the ability of a single class to take on many forms.
The essence of polymorphism is this: at times you will know you have a collection of a
general type, eg a collection of Vehicles. You do not know (or care) what the specific subtype
each of your vehicles is (one may be a car, another a truck, etc). The important thing is that
you know they all inherit shared abilities (eg the turn-left method) and that you can treat them
all as vehicles. If you write a program instruction that tells each control to turn-left, this is
implemented properly on a per-vehicle basis. You do not need to know how each derived
class accomplishes this; you only need to know that each class is defined to be able to turnleft.
Polymorphism allows you to treat a collection of disparate derived classes (cars, trucks, vans)
as a group. You treat the general group of objects in the same way, and each individual object
does the right thing according to its specific type.
Defining Classes
Object behaviour is created by writing methods. A method is a small routine that every
object of the class can execute, eg an Array class might have a sort method.
Object state is maintained by variables. Variables can be primitive types (eg an int to hold
the age of a person), or variables can be objects of other classes (eg an Employee class may
have a field of type Address).
To define a new class, you first declare it and then define its methods and variables In Java
everything happens within a class; no method can run outside a class.
Methods
The name "method" is part of object-oriented terminology. Methods replace functions and
procedures from non-object-oriented languages. Methods may or may not return a value, and
the may or may not have one or more parameters.
To make your methods as flexible as possible, you can define parameters: information passed
into the method when the method is called. Thus, rather than having to write one method
when you want to sort your ListBox from A-Z and a second to sort it Z-A, you define a more
general sort() method and pass in a parameter specifying the order of the sort.
Methods can take any number of parameters. When a method is defined, the parameter list
follows the method name and is encased in parentheses. Each parameter's type is identified
before the name of the parameter.
For example, the following declaration defines a method named MyMethod() which takes
two parameters, an integer and a double:
public void MyMethod(int firstParam, double secondParam) {
'
'
'
}
The parameters act as local variables, as if you had declared them in the body of the method
and initialised them with the values passed in.
All parameters in Java are passed by value. Pass by value means that a local copy is made of
the value and assigned to the parameter inside the method. It is this local copy that is used
inside the method.
When the parameter is of a primitive data type, any change to the value of that parameter
within the method, does not change anything in the calling method.
It is a little more complicated when the parameter is an object. In this case what is passed as
the parameter is a reference to the object. A local copy is made of this reference but this will
refer to the same object as the original reference. Thus any changes to the object's state made
are made on the original object.
Using Static Members
The variables and methods of a class can either be instance members or static members.
Instance members are associated with instances of the type, while static members are
associated with the class, and not with any particular instance. Methods are instance methods
unless explicitly marked with the keyword Static.
The majority of methods will be instance methods. The semantics of an instance method are
that you are taking an action on a specific object. However it is sometimes convenient to be
able to invoke a method without having an instance of the class, and for that you use a static
method.
You normally access a static member through the name of the class in which it is declared.
This allows you to access the static member without having an instance of the class. A
common use of static variables is to keep track of the number of instances (objects) that
currently exist for your class.
It is also legal to access static members using an object name but the compiler will substitute
the class of the object at compile time. Although it is normal to use the class name when
referring to static members the SCJP exam may well try to confuse you by sometimes using
an object name.
Constructors
Consider this statement that creates an Employee object, it looks as though it is calling a
method:
Employee barney = new Employee()
Actually, a method is called whenever you instantiate an object. This method is called a
constructor. Each time you define a class, you are free to define your own constructor, but if
you don't, the compiler will provide one for you invisibly and automatically. The job of the
constructor is to create the object specified by a class and to put it into a valid state.
Destroying Objects
You do not normally need to worry about cleaning up after your objects, they are
automatically destroyed when you are done with them (ie the memory they use is freed-up
and so can be reused). Java has a "garbage collector" which does this for you. Thus you do
not need "Destructor" methods.
Download