Object Oriented Programming/Design F.A.Q.
Table of Comments
1 Object Terminology
2 Object Oriented Programming
3 Object Oriented Design
4 Process/Methodolgy
5 Other Paradigms
6 CASE tools
1 Object Terminology
1.1 What does it mean for software to be
object oriented?
Object oriented software is a term used to describe a program
built using object oriented techniques. It is also used to
describe a methodology for building software systems. In
general, it boils down to the idea that everything in the system
is an object. The behavior of the system is then defined as the
operations the objects can perform. The available behaviors are
usually implemented by building relationships between the
objects. Object oriented software is often called
noun-centric software. For example, in an accounting program, important
objects may be accounts, ledgers, debits, and credits.
1.2 What is a class?
A class is a definition of data and operations on that data. It is
one of the fundamental building blocks of object oriented
programming. In general an object oriented program is composed of
various classes and the relationships between those classes. A more
formal definition of a class might include that classes have
invariants, much like loops. During the lifetime of an instance of a
class, the invariant should always be true from the perspective of the
class's clients. Operations within the class are allowed to
violate the invariant temporarily with the understanding that
the invariant will be true by the time control is tansferred
back to the client.
1.3 What is an instance?
An instance is an instantiation of a class. Essentially, the class
describes what the data types and methods available to
the instance, while the instance holds the values of those
types.
1.4 What is encapsulation?
Encapsulation is the idea that data and the methods that operate on
that data should be maintained together in a single unit (usually a
class definition).
1.5 What is polymorphism?
Polymorphism is the mechanism that allows a single method invocation
to call different operations for different types. One does not need
to know the specific type of object in order to invoke the operation,
only that the object supports the given operation. This technique is
often used in concert with inheritance, so that the user has a handle
to an abstract base class of the object, and when the client invokes
the operation the correct method in the concrete class is invoked.
Polymorphism can be correctly used in describing method determination
thru static type inference as well (sometimes called static or parametric
polymorphism -- see "What is generic programming?").
1.6 What is association?
Association is the relationship between two classes, where one class
maintains a reference to another class. This association is often
described as the "hasA" relationship because it often models the idea
of one class having another class. For example, suppose you had
developed a class for an advertising agency. An agency could have an
association to a client, because a agency "hasA" client (to be
successful, it probably needs to have more than one, but we'll talk
about cardinality later).
1.7 What is aggregation?
Aggregation is a relationship between two classes, where one class
contains another. Aggregation comes in both a weak form and a strong
form. The weak form, sometimes called loose aggregation, means that
the class instance that is aggregated into another class instance does
not have its lifetime managed by the other class. The strong form of
aggregation, somtimes described as a "composedOf" relationship, means
that if the aggregate is destroyed, the aggregated class is also
destroyed. The differences between the two forms of aggregation and
association are subtle enough that it is probably beneficial to expand
upon the example used for association. In addition to having
clients, lets suppose that our agency is made up of agents and
contracts. If one were to dissolve the agency, naturally the
contracts would be dissolved as well. So it is fair to say that
the agency is composedOf contracts (not wholly mind you, but
partially). On the other hand, if the agency were dissolved,
the agents would continue to exist most likely, however their
role in the system would be changed (perhaps they
would become free agents). The agents are loosely aggregated
by the agency. Obviously the business could be one where the
agents could not exist outside of the agency, in which case
strong aggregation would be the preferred relationship.
1.8 What is inheritance?
Inheritance is the relationship between two classes, where
one class is
a specialization of the other class. The simplest way to describe it
is to show a trivial example. If you already had a class called
Airplane that described the basic data and operations of an
airplane, and then later determined that in addition to your
standard airplane, you also need to define a CargoAirplane, you
might find it useful to have
CargoAirplane inherit from Airplane, especially if all the data
and operations
that apply to an Airplane also apply to a CargoAirplane. The
CargoAirplane class can then add any data useful to a cargo
airplane (e.g. carryingCapacity). The class that is
inherited from is
often called the base class, and classes that inherit from the base
class are often called derived classes. If a base class defines
methods but does not give a callable default implementation, than the
class is also abstract. In order to instantiate a derived class, it
must implement the methods that do not have a callable
implementation. These classes are sometimes called concrete derived
classes. Sometimes the goals of inheritance are further qualified.
Interface Inheritance is when classes derive from a base class to
provide a specialized implementation of the base interface.
Implementation inheritance is when a derived class wishes to leverage
some functionality in a base class by way of inheritance. An often
overlooked negative with the inheritance relationship is that it is
not unusual to have the derived class coupled to the base classes
implementation. For more information on coupling see the item
on coupling.
2 Object Oriented Programming
2.1 What are some languages that allow object oriented
programming?
In order to implement object oriented programming, a programming
language needs only to support inheritance, polymorphism, and
encapsulation. The following is a list of some of the more
popular (or at least historically noteworthy)
languages offering explicit syntactic support for object oriented
programming:
Simula (1967)
Smalltalk (1980)
Ada (1981)
C++ (1982)
CLOS/LISP (1986/1959)
Python (1990)
Dylan (1992)
Java (1994)
C# (2001)
In addition, some languages don't offer explicit syntactic support for
all the features of OO, but you can emulate them effectively using
convention.
2.2 What is the best programming language for
object oriented programming?
Every language has its own advocates. A good place to find
out information about each of the languages above are their
respective newsgroups:
comp.lang.smalltalk
comp.lang.smalltalk.advocacy
comp.lang.ada
comp.lang.c++
comp.lang.c++.moderated
comp.lang.lisp
comp.lang.python
comp.lang.java
comp.lang.java.advocacy
comp.lang.dylan
comp.lang.csharp
2.3 Is garbage collection neccesary for object
oriented programming?
No. Though many languages that explicitly support object oriented
programming have garbage collection as the default memory handler
(Smalltalk, Java, etc.) or support garbage collection in terms of an
addin library (C++). Many programmers prefer not to deal with the
hassles of memory management, but other programmers are of the opinion
that memory management issues are too important to be left to the
language implementation.
2.4 Which is better, dynamic typing or static
typing?
They both have their advantages. Static typing is the process
where a tool (usually a compiler) is used
to determine if a program declares variables of an incomplete type
before that type has been defined. Dynamic typing is the process
where the type of a variable is verified only when that variable is
first used. Some languages that use static typing are Ada, C++,
Java, and Dylan. Some languages that use dynamic typing are
Smalltalk, Lisp, and Dylan. Static versus dynamic typing is
independent of object oriented programming, but here is a quick
argument for each, respectively:
Static typing is safer. Type checking is a tedious process best
performed by computers. In the case where one does not test every
execution path, you can at least be guaranteed that there will not be
a type exception.
Dynamic typing is more flexible. It allows you to more easily develop
your code, as it does not require that the code be developed in any
specific order (e.g. making you fully specify a type before using
it). The safety issue is a chimera, because you must test every
execution path regardless.
2.5 What is dual (or multiple) dispatch?
Dual dispatch is the mechanism that allows a method invocation to
determine the implementation based on the type of both arguments to a
function, rather than only the type of the first object. Many object
oriented languages do not support this feature explicitly, and the
dispatch mechanism has to be hand coded. Other languages (such as
Dylan, and Lisp) do offer explicit support for multiple
dispatch.
2.6 What is subtyping, and how is it related
to inheritance?
A is a subtype of B if the set of all possible values for A
are contained within the set of all possible values for B. This
is a slightly different than the
definition given by Barbara
Liskov, but in essence the definitions turn out to mean the same
thing in the mathematical sense. Some languages choose to
implement subtyping via inheritance (e.g. C++ and Java), many
other languages don't make this distinction.
2.7 What is a "mixin" class?
A mixin is a class that is derived from in order to access the
mixin's implementation. See
implementation inheritance.
3 Object Oriented Design
3.1 What is object oriented design?
During object-oriented analysis the high level actors and tasks are
typically identified and documented. Object oriented design is the
process of converting the actors and tasks into classes, and describing
the interactions between the identified classes. The unified modelling
language, UML, is often used to document the discovered classes and
interactions. TODO: Add example and more info.
3.2 What is coupling?
Coupling is another name for class relationship. Whenever the term
coupling is used, though, the goal is generally to talk about the number
of relationships a class has, and the nature of the relationships. For
example, a class is tightly coupled to another class if the former is
heavily dependent on the latter (e.g. a wrapper class). Coupling isn't
bad in and of itself, however it often turns out to be the source of
problems. Classes that have a high degree of coupling are often more
difficult to understand
3.3 What is layering?
TODO: Add description and example.
3.4 What is UML?
UML is an acronym for the Unified Modelling Language. It is a
graphical notation for representing the relationships between classes,
packages, and components. It also includes a notation for capturing
requirements (use case diagrams). The "unified" part of the name
comes from the creators of the language, Booch, Rumbaugh, and
Jacobson. Each combined components of their original notation to
create a sindle standardized modelling language.
3.5 What is LSP (the Liskov Substitution
Principle)?
Barbara Liskov wrote in a paper to the ACM:
Family
Values: A Behavioral Notion of Subtyping. Essentially
this boils down to the idea that A is a subtype of B, if an
instance of A can be substituted anywhere an instance of B is
needed. Another way to think about this is that derived classes
cannot violate the invariants of their base classes. This
principle is often used to critique designs where a class
inherits from another, but attempts to cripple some
functionality of the base class. Of course the canonical
example is circle/ellipse. Is circle a subclass ellipse? This
issue has been discussed to death on the newsgroup comp.object.
The answer depends on how exactly ellipse is defined and even
which the language being used for implementation..
3.6 What is the Open Closed principle?
Simply stated, the open closed principle is the idea that
classes are "open" for addition, and "closed" for modification.
More completely, when modifying class, you should strive to add
methods, rather than change existing methods. In order for
modifications that follow this idiom to work, the class needs to
be designed in such a fashion that functionality can be added in
base classes, but used transparently by the parent classes
interface. An example of two patterns that exemplify this
principle are the strategy pattern and the visitor pattern.
3.7 What are patterns?
Patterns are attempts to document useful programming idioms.
For an idiom to qualify as a pattern it generally must be proven
to be useful in several different applications. Patterns (at
least the object oriented type) usually attempt to document a
way of relating classes that is particularly useful at solving a
common problem. I've gone to the trouble to mention some of the
more popular or useful patterns, but there is a whole ream of
literature on patterns, how to find new ones, and how to
document them. A good place to start is Design Patterns:
Elements of Reusable Software by Gamma, et all.
3.7.1 What are creational patterns?
Creational patterns are probably the most widely used
patterns, at least partially because they have the advantage of
being non-controversial. Other categories of patterns don't
always have that property. Creational patterns are proven
idioms for constructing and initializing objects. Most object
oriented software probably utilizes several of these patterns in
some shape or form.
3.7.1.1 What is the Singleton Pattern?
A creational pattern that ensures that only one instance of a class
can be instantiated. It also provides an encapsulated interface for
accessing the singleton. The singleton pattern comes in many
flavors, at least partially because the idea is so useful people
have attempted to use it in situations it did not neccesarily
fit well. Refer to Design Patterns: Elements of Reusable
Software for a complete description of the singleton
pattern.
3.7.1.2 What is the (Abstract) Factory
Pattern?
TODO
3.7.2 What are behavioral patterns?
TODO
4 Process/Methodology
4.1 Is a methodology required for object-oriented development?
It depends. It definitely isn't required to use any well known
methodology (often called big M, Methodologies). It is possible
to develop object oriented code in an unstructured fashion, but it
is generally preferable to develop the code with a little more
structure, as class relationships can lead to excessive coupling.
Often a process can help reduce coupling by requiring some degree of
forethought be put into developed code, however there is no
guarantee that any process will help deliver good software.
4.2 What is an iterative process?
An iterative process is one that attempts to build systems
incrementally. A subset of the requirements is chosen for each
iteration and developed to completion. Generally this means that
the software for those requirements is designed and coded
together. Then another set of features are designed to be added
to the existing system and developed. One advantage of this
approach is that the system can accomplish some of the required
tasks after the first iteration, and then becomes more and more
full featured after every iteration. Another advantage is that
requirements are notoriously volatile, and this approach can help
mitigate some of the risk of requirements change by not having
spent any effort on requirements that have not been thru an
iteration yet.
4.3 What is the waterfall process?
4.4 What is Extreme Programming?
Extreme programming, sometimes shortened to XP, is a relatively new
methodology advocated by several
respected industry veterans. The chief originator of Extreme
Programming was Kent Beck, who developed the process for a
project at Chrsyler called C3. Extreme programming is a so called
lightweight process, meaning that it is a process that has little
overhead and few rules. While strictly true, the XP rules alter
the way developers work radically and is quite demanding in its
application. The original 12 rules of XP are:
- System Metaphor - Develop a metaphor for the system
- Planning Game - a way to prioritize requirements
- Small Releases - the planned releases should be small (every 2
weeks is a guideline often used)
- Acceptance Tests - Every release must have a set of automated
acceptance tests
- Pair Programming - All production code is written in pairs
- Test First Design - All production code is written to pass a
unit test
- Simple Design - All software is written as the simplest thing that
could possibly work
- Continuous Integration - The software should be integrated daily
- Refactor Mercilessly - Code refactoring should be done as soon
as a need for refactoring is observed
- Collective Ownership - No specialization, everyone works on all
the code
- Sustainable Pace - No overtime or pre delivery rush
- Onsite Customer - The customer must be available to answer team
questions and participate in team activities
More information is available on the newsgroup
comp.software.extreme-programming.
4.4 What is RUP(Rational Unified Process)?
RUP isn't actually a set of rules that make up a process, rather it
is a set of rules that describe how a particular process would have to
be tailored to be RUP-compatible.
5 Other Paradigms
5.1 What is a procedural/imperative
programming language?
Imperative programming is essentially programming directly to the
computer. Valid operations are assignments, memory allocation and
deallocation, value swaps, math operations etc. Procedural
programming is imperative programming with the addition of being able
to organize imperative statements into reusable blocks. This style of
syntax is common to Ada, C++, Dylan, Java, and Smalltalk. Lisp has
many features of an imperative programming language.
5.2 What is a declarative/relational
programming language?
Declarative programming is programming to generate logical closures.
The program is a set of rules, and a supposition. The supposition is
consistent with the rule set, or it is not. An example of a
declarative system is a Makefile. The supposition is usually
something along the lines of, "Is an executable up to date?".
In determining if the executable is up to date, any out of date
files will be recompiled to generate the object code, and the
executable will be linked. Essentially the executable is always
up to date after the supposition is posed. This is a common
technique in declarative systems.
5.4 What is functional programming?
Functional programming is one implementation of declarative
programming. The rule definitions are supplied as functions that then
locate other rules. Functional programming is widely used in
academic circles, perhaps partly because it has an associated
calculus (lambda calculus) that proves its completeness. The
existince of lambda calculus also lends some of the proponents
of functional programming to consider the solutions elegant.
One of the most popular functional programming language(s), LISP
(it has many dialects), however also has many procedural
artifacts. Though not needed for completeness, the procedural
components sometimes allow more straightforward or efficient
solutions to problems (for example the ability to use a loop in
place of recursion).
5.5 What is generic programming?
Generic programming is another implementation of declarative
programming. It is unique from the other two major flavors of
declarative (functional and relational) programming in that it is widely
applied in industry and is not of academic origin. The most popular
application of generic programming, the C++ STL, is
the brainchild of Alexander Stepanov. Though the mechanism is the same
as the other declarative languages, the application is slightly
different. Rather than controlling business logic, generic
programming is used to generate type specific code. Declarations
compose generic algorithms that are then applied to the type
specified by the application. It would be fair to call
programming based on this style algorithmic programming, as the
algorithms are the chief items abstracted in the code rather than
the specific business objects. Variations on this technique can
be used for aspect oriented programming.
6 CASE tools
6.1 What is a CASE tool?
CASE is an acronym for Computer Aided Software Engineering. CASE
tool refers to tools that purport to raise productivity by allowing
programmers/designers to work more effectively. In general
every software project needs some tools. Makefiles, source
control, and bug tracking are some of the least controversial.
However there are also tools that supposedly help at managing
the project space by allowing the enegineers to better model the
problem they are solving. An example of this kind of tool could
be a UML drawing tool or requirements management software, but
there are far too many types to list.
6.2 What CASE tools should I use?
It is impossible to give a solid recommendation to this question. It
depends on a great many factors, including, but not limited to team
size, scope of project, geographic location of team members. Some
CASE tools that projects have found effective include UML modelling
tools, refactoring browsers, pretty printers, static checkers, bounds
checkers, etc. Still other prefer whiteboards and markers. No
matter what CASE tools you choose it is important to understand
their limitations. CASE tools don't actually produce working
software, they just try to facilitate the development of better
software. Accordingly, CASE tools alone are not the answer.