Object-Oriented Concepts

Objects, Classes, and Packages

Object = Identity + Operations + Attributes

An object is anything-- concrete or abstract-- that has attributes and that can perform certain operations.

A typical operation might change one of the object's attributes, calculate something, report an answer, and/or ask another object to perform one of its operations.

We call the current values of an object's attributes its state.

For example, a bank account is an object that performs three operations:

account.withdraw(25.25);
account.deposit(32.18);
account.getBalance();

The account performs the first operation by deducting $25.25 from its balance, and performs the second operation by adding $32.18 to its balance. We can think of the balance as the account's state:

account.balance

The account performs the last operation by reporting its current balance to the operation's requestor.

Examples of real-world objects include:

a vending machine
a computer
a calculator
a computer chip
a car
a checking account
a business

Examples of software objects include:

a bank's computer record of a checking account
the DMV's computer record of a car
a word processor
a word processor's internal representation of a document
a document's internal representation of a paragraph

Type = Operations

The set of operations an object performs is called the object's type.

For example, a bank account performs three operations:

withdraw some amount of money
deposit some amount of money
get the current balance

Formally, all bank account objects have the type:

type AccountType {
   void withdraw(Money amount);
   void deposit(Money amount);
   Money getBalance();
}

Class = Type  + Methods + State Space

The state space of an object is the set of all legal states the object can be in.

For example, the state of an account is its balance. The state space is the set of all possible amounts of money. Illegal amounts of money might be $-200, $3.999, or infinity dollars.

A method is an operation together with its implementation (algorithm, procedure, body).

For example, a bank account implements the deposit operation by adding a specified amount of money to its balance.

The set of methods an object performs is called its behavior.

The class of an object is its state space and behavior.

Alternatively, we can think of a class as a template for creating objects with certain states and behavior.

We say that an object is an instance of its class.

Formally, all bank accounts are instances of the class:

class Account {
   Money balance;
   void withdraw(Money amount) {
      this.balance = this.balance - amount;
   }
   void deposit(Money amount)  {
      this.balance = this.balance + amount;
   }
   Money getBalance() {
      return this.balance;
   }
}

Note:

this = the object performing the operation

Examples of classes:

all employees of Acme Corp.
all products manufactured by Acme
all computers on the Acme network
all sales transactions conducted by Acme
all forms created by Acme

all geometric curves
all polynomials
all vectors

Package = Classes + Sub-packages

A package is simply a named group of related classes and sub-packages.

Examples of packages and some classes they contain:

geometry.geometry2d
geometry.geometry3d
geometry.geometry2d.Point
geometry.geometry2d.Curve
geometry.geometry3d.Point
geometry.geometry3d.Curve
geometry.geometry3d.Surface

business.Account
business.Transaction
business.Customer
business.Employee

dbase.Table
dbase.Row
dbase.Query
  

UML Class, Object, and Package Icons

The UML icon for the Account class:

We can also show the attributes and operations:

Sometimes, if we are feeling lazy or lack details, we simply write:

UML icons representing instances of the Account class (i.e., account objects):

UML icons representing packages:

Dependency relationships between classes

A UML class diagram is a network of class icons connected by lines segments. The line segments represent relationships

Association (has-a)

Every instance of Customer has an instance of class Account.

Associations are implemented as attributes:

class Customer {
   Account myAccount;
   ...
}

Aggregation (part-of)

There are two part-of relationships in UML: aggregation or hollow-diamond aggregation, and composition, or solid diamond aggregation.

Aggregation is the relationship between a collection (set, list, etc.) and the items it contains.

Composition is the relationship between an assembly and its components.

For example: A fleet is a collection of airplanes. An airplane is an assembly of components such as wings, engines, and controls.

Many languages provide libraries of collection classes for representing aggregates:

class Fleet {
   Set<Airplane> members;
   ...
}

class Diary {
   List<Entry> entries;
   ...
}

Dependency (uses-a)

Class A depends on class B if some change in B causes a change in A. Usually this happens if A uses or refers to B. Association, aggregation, composition, and extension (see below) are all special cases of the dependency relationship.

Also, A uses B if one of A's methods uses B.

For example, a method uses class B if one of its inputs is an instance of B or if it uses an instance of B internally.

class TaxCalculator {
   TaxTable married, single, headOfHousehold;
   Money computeTax(W2Form income) { ... }
   ...
}

The Law of Demeter

The Law of Demeter frowns on implicit references such as the implicit reference between VirtualAccountant and TaxTable in this example:

class VirtualAccountant {
   TaxCalculator calculator;
   int computeWitholding(W2Form income) {
      Money tax = calculator.single.lookupTax(income);
      ...
   }
   ...
}

Instead, make implicit references disappear:

class VirtualAccountant {
   TaxCalculator calculator;
   TaxTable married, single, headOfHousehold;
   int computeWitholding(W2Form income) {
      Money tax = single.lookupTax(income);
      ...
   }
   ...
}

or make them explicit:

class VirtualAccountant {
   TaxCalculator calculator;
   int computeWitholding(W2Form income) {
      Money tax = calculator.lookupTax(income);
      ...
   }
   ...
}

Generalization = Specialization = Extension (is-a)

Class A specializes class B if every operation of B is also an operation of A. We also say that A extends B or that B generalizes A.

Extensions in Java, C#, and C++ must be explicitly declared:

class Document { ... }
class Form extends Document { ... }
class TaxForm extends Form { ... }

class Document { ... };
class Form: public Document { ... };
class TexForm: public Form { ... };

Inheritance

Note that class A extends class B says the operations of B are among the operations of A, but it does not imply that the methods or attributes of B are also methods or attributes of A, although this is frequently the case. The author of A may choose to implement A's operations any way he chooses and these implementations may choose to ignore B's state space.

In languages like Java, C++, and C# declaring that A extends B means that A automatically inherits the attributes and methods of B. This saves a lot of work since it means that the author of A doesn't need to copy the desired methods and attributes of B. Instead, he simply needs to redefine or override the methods of B that he wants to change.

Subclasses

The subclass relationship is the transitive closure of the extends relationship. We abbreviate "A is a subclass of B" by writing:

A <: B

Here are the formal rules:

A <: A
A extends B implies A <: B
A <: B and B <: C implies A <: C

For example:

TaxForm <: Form <: Document

and so:

TaxForm <: Document

It's easy to see that in languages that support inheritance:

A <: B implies A inherits the methods and attributes of B

Subsumption Rule = Polymorphism = The Liskov Substitution Principle (LSP)

If A is a subclass of B, then we should be able to use an instance of A in any context where an instance of B is expected. For example, assume the print method of a printer expects a document as an input:

class Printer {
   void print(Document doc) { ... }
   ...
}

According to the subsumption rule printers should also be able to print W2 forms:

Printer myPrinter;
W2Form myW2Form;
...
myPrinter.print(myW2Form);

We have to be careful, because although an instance of the subclass performs the same operations an instance of the super-class performs, the actual implementation might be different.

For example, assume Square extends Rectangle, but overrides methods for changing the height and width in order to keep height and width equal. This could be an unpleasant surprise to a user who didn't realize that he was dealing with a square instead of a rectangle.

Encapsulation

The scope or visibility of a class, method, or attribute refers to the region of the program where the method or attribute can be used. In order of decreasing size, the scopes available in Java are:

program scope
subclass scope
package scope
class scope
block scope

A class can control the scope or visibility of its attributes and methods. The general rule of thumb is:

Scopes should be as small as possible, but not smaller!

Usually attributes and helper methods have class scope while all other methods have program scope.

- = private = class scope
# = protected = sub-class scope
~ = package = package scope
+ = public = system/program scope

For example:

In Java:

public class Account {
   private Money balance;
   public void withdraw(Money amount) {
      this.balance = this.balance - amount;
   }
   public void deposit(Money amount)  {
      this.balance = this.balance + amount;
   }
   public Money getBalance() {
      return this.balance;
   }
}

Decorating associations

Multiplicity: A customer owns 1 to 5 accounts.

Navigation: A customer knows the accounts he owns, but accounts don't know the customers who own them:

class Customer {
   Account account1, account2, account3, account4, account5;
   ...
}

Or use an array of fixed size:

class Customer {
   Account[] accounts = new Account[5];
   ...
}

Multiplicity: A customer owns zero or more accounts:

class Customer {
   Set<Account> accounts;
   ...
}

Roles: A customer knows the accounts he owns, accounts know their owners. An account refers to its owner as its holder:

class Account {
   Customer holder;
   ...
}

Package Diagrams

Package p1 uses or depends on package p2 if some of the members of p1 use some of the members of p2. We also say that p1 imports from p2 or that p2 exports to p1. In UML:

The Acyclic Dependency Principle suggests that cycles in package diagrams should be avoided.

Object Diagrams

An object diagram shows objects and the links that connect them. Just as an object is an instance of a class, a link is an instance of an association. For example, assume customer smith owns a checking and savings account: