Java Reference
Object-Oriented Basics:
Objects have state and behaviour, modeled by class variables and methods that act on those class variables.
- Encapsulation — hiding the implementation and protecting the internal state of an object from being manipulated by external objects. Encapsulation helps abstract away the inner workings and present high-level functionalities
Eg. when a
human
drives a car
, that human
invokes methods on the car
without knowing anything about the implementation of those car
methods
- Good encapsulation helps objects have a more consistent and predictable internal state
- It's easier for us to work with an interface
- Inheritance — models "is-a" relationships between classes. New classes can 'inherit' the fields and methods of an existing class through inheritance.
- When inheriting methods that aren't valid for the subclass, we can method override to add our own implementation
- Only use inheritance when most or all of the inherited fields and methods make sense when inherited
- Enables runtime polymorphism
- Polymorphism — to present the same interface for differing underlying data types.
Eg. instances of
Circle
and Rectangle
can be treated as an instance of type Shape
- Allows objects having different internal structures to share the same external interface.
- Polymorphism allows the object to decide which form of the method to use at compile-time as well as run-time — "the ability of different objects to respond, each in its own way, to identical messages"
- Allows subclass objects to be treated as base class objects.
Eg. a
List<Shape>
can store Circle
, Rectangle
, etc. and with dynamic binding, calling methods exposed on the Shape class will invoke the 'correct' methods based on whether the object is a Circle
, Rectangle
, etc.
- Association — "has-a" relationships between objects.
- Association is when an object stores a reference to another object — which it may use to keep track of its own internal state as well as forward methods to
- "has-a" or "is-composed-of" relationships, are usually preferred over inheritance — "favour composition over inheritance".
- Types of associations:
- Aggregation — "has-a" — if
A
has a B
, then instances of B
can exist without being associated to an instance of A
- Composition — "is-composed-of" — if
A
is composed of B
, then all instances of B
must be associated with an instance of A
UML Diagrams:
UML class diagrams — unified modelling language — is a useful abstraction over object-oriented design for capturing the semantics of requirements. Before implementing a network of classes, we need to have a conceptual understanding/overview of the system
- UML is a graphical notation that is more precise than natural language and less detailed than code
UML Examples:
Class:

Object:

Inheritance:

Association:

Aggregation:

Composition:



- Association — a semantically weak relationship between otherwise unrelated objects. Association represents a 'uses' relationship between 2 or more classes each of which have their own lifecycle. There's no idea of "ownership" in regular associations
- Eg. Consider the classes:
tutorial
, tutor
and student
— deleting the tutorial instance doesn't mean the tutor and student should also be deleted.
- Aggregation — a specialised unidirectional association where 2 or more classes have their own lifecycle BUT there is "ownership"
- Eg. A
car
has a brake
, an engine
, door
, etc. but these components can exist independently from a car. Another example: wallet
has money
, but not conversely
- Composition — a specialised aggregation where if the parent object is destroyed, the child will also be destroyed because it can't exist independently of the parent instance. Also called "death relationship"
- Eg. A
human
has a heart
, and if an instance of human
is destroyed, then so is the instance of heart
Aggregation vs. composition example:

A house contains exactly 1 kitchen, 1 bathroom, 1 mailbox, 1 or more bedrooms and at most 1 mortgage. When the house is destroyed, the mailbox can still exist.
Software Design Principles:
Design Smells:
- Rigidity — difficulty in modifying the program. Maybe one small change requires a cascade of changes in dependent modules
- Fragility — tendency for the software to break when making minor changes
- Immobility — difficulty in reusing the software
- Viscosity — difficulty of adding design-preserving code
- Opacity — overexposure of implementation details
- Needless complexity — how much of the codebase isn't relevant to the requirements?
- Needless repetition — how badly is the DRY principle being violated?
Code Smells:
- Duplicate code — violating DRY principle
- Poor abstraction — where a change in one place necessitates a change in other places
- Large and complex bodies of code — anytime there are several layers of nesting, long parameter lists, long methods, etc.
- Classes have too little cohesion — handling too many different things. There's no 'theme' to the class
- "Data class" has little functionality — eg. validity checks
Coupling and Cohesion: