0% found this document useful (0 votes)
16 views29 pages

INFO404 Reference

The document provides notes on object-oriented programming concepts like encapsulation, polymorphism, and inheritance. It also covers string methods, accessors and mutators, inheritance and type mismatch issues, final and abstract classes, reflection and generics, and collections like lists, sets, and maps. Key collection interfaces discussed include Collection, List, Set, Iterator, and ListIterator. Common collection classes mentioned are LinkedList, ArrayList, HashSet, and AbstractCollection. The notes also provide examples of equals and hashCode methods for classes and subclasses, as well as shallow and deep cloning.

Uploaded by

Boshra Ismail
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views29 pages

INFO404 Reference

The document provides notes on object-oriented programming concepts like encapsulation, polymorphism, and inheritance. It also covers string methods, accessors and mutators, inheritance and type mismatch issues, final and abstract classes, reflection and generics, and collections like lists, sets, and maps. Key collection interfaces discussed include Collection, List, Set, Iterator, and ListIterator. Common collection classes mentioned are LinkedList, ArrayList, HashSet, and AbstractCollection. The notes also provide examples of equals and hashCode methods for classes and subclasses, as well as shallow and deep cloning.

Uploaded by

Boshra Ismail
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

NotesHassan.

md 2024-02-06

INFO404 Notes
by Hassan Maouch

General Notes:

Object-Oriented Programming Concepts:

Encapsulation, Polymorphism & Inheritance relate to object-oriented programming while garbage


collection does not.
Equals method should be used to compare Objects
equals() and hashCode() must be compatible
if x.equals(y) is true => x.hashCode() == y.hashCode()
if x.hashCode() == y.hashCode() then x.equals(y)

String Methods:

String.indexOf(“char”,nb); => returns the index of the nth repetitive char (indexing starts from 0)
String.split(“char+”)[nb]; => (indexing starts from 0) returns the rest of the word after the nth
repetitive char
String.split(“char”)[0]; => returns from the beginning of the word till the first occurrence of char

Accessors and Mutators:

Mutators => setters


Accessors => getters

Inheritance and Type Mismatch:

Superclass: A = new subclass: B is accepted


Subclass: B = new superclass: A is rejected => !! type mismatch !!
Dynamic binding is the operation to select the correct method at runtime

Final and Abstract Classes:

To prevent inheritance use “final” this ensures no changes in the subclass (the class & methods)
Abstract classes: no implementations in the abstract method of the abstract class, subclasses of abstract
superclass must implement abstract methods

Reflection and Generics:

Reflection: is the ability to find out more about classes and their properties in a running program
Generics type: E (elements), K & V(key and value), T,U,S & W for all types
Wildcard / the Joker “?”
Bounded: Set/List/.. < ? extends className >, List < ? super className >
Unbounded: without super or extends

Collections:

List ➔ order, duplicate → LinkedList, ArrayList

1 / 27
NotesHassan.md 2024-02-06

ListIterator: list + has 2 more functions → hasPrevious, previous


Set ➔ no order, no duplicate
TreeSet is ordered
Map ➔ key & value
collision => two unequal objects hash to the same slot

Other Important Points:

We can’t create an object of an abstract type


Due to polymorphism, an object of declared type behaves differently during the execution according to
its actual type
Main functions are always static
Static function => not accessing the fields of the class
In collections, we can not call remove if not proceeded with next()

Equal methods:

1. Check reference
2. Check if is not null
3. Check if they are the same type
4. Compare attributes

Super class:

public Boolean equals(Object otherObject){


if (this == otherObject) return true;
if (otherObject == null) return false;
if(this.getClass() != otherObject.getClass()) return false;
className object = (className) otherObject;
return this.att1 == object.att1 && Objects.equals(this.att, other.att) && … ;
}

public int hashCode(){


return Objects.hash(att1, att2, ..);
}

Subclass:

public Boolean equals(Object otherObject){


if (!Super.equals(otherObject)) return false;
subName other = (subName) otherObject;
return this.att1 == object.att1 && Objects.equals(this.att, other.att) && … ;
}

public int hashCode(){


return java.util.Objects.hash(super.hashCode(), att); //the added attributes
}

2 / 27
NotesHassan.md 2024-02-06

Shallow Clone:

public className clone() throws CloneNotSupportedException {


return (className) super.clone();
}

Deep Clone: Same as shallow clone in implementing and access modifier and throwing plus clone also the
mutable objects then return // mutable = changeable

public class className implements Cloneable {


public className clone() throws CloneNotSupportedException {
className cloned = (className) super.clone();
cloned.att = (type) att.clone();
return cloned;
}
}

Collections

Interface Collection<E>

public interface Collection<E> extends Iterable<E>

Iterable allows the use of foreach: for (T t: this)

The most 2 important (Abstract) functions:

boolean add(E e): Ensures that this collection contains the specified element (optional operation).
Iterator<E> iterator(): Returns an iterator over the elements in this collection.

Interface Iterator<E>

public interface Iterator<E>

It is illegal to call remove() if not preceded with next()

Default methods:

void forEachRemaining(Consumer<? super E> action): Performs the given action for each
remaining element until all elements have been processed or the action throws an exception.
boolean hasNext(): Returns true if the iteration has more elements.
E next(): Returns the next element in the iteration.

3 / 27
NotesHassan.md 2024-02-06

default void remove(): Removes from the underlying collection the last element returned by this
iterator (optional operation).

Interface Iterable<T>

public interface Iterable<T>

Default method:

default void forEach(Consumer<? super T> action): Performs the given action for each
element of the Iterable until all elements have been processed or the action throws an exception.
Iterator<T> iterator(): Returns an iterator over elements of type T.

Class AbstractCollection<E>

public abstract class AbstractCollection<E> extends Object implements


Collection<E>

In order not to implement all Collection functions, we use this class.

Abstract method:

abstract Iterator<E> iterator(): Returns an iterator over the elements contained in this
collection.

Interface ListIterator<E>

public interface ListIterator<E> extends Iterator<E>

All abstract methods:

void add(E e): Inserts the specified element into the list (optional operation).
boolean hasNext(): Returns true if this list iterator has more elements when traversing the list in the
forward direction.
boolean hasPrevious(): Returns true if this list iterator has more elements when traversing the list in
the reverse direction.
E next(): Returns the next element in the list and advances the cursor position.
int nextIndex(): Returns the index of the element that would be returned by a subsequent call to
next().
E previous(): Returns the previous element in the list and moves the cursor position backwards.
int previousIndex(): Returns the index of the element that would be returned by a subsequent call
to previous().

4 / 27
NotesHassan.md 2024-02-06

void remove(): Removes from the list the last element that was returned by next() or previous()
(optional operation).
void set(E e): Replaces the last element returned by next() or previous() with the specified element
(optional operation).

Interface List<E>

public interface List<E> extends Collection<E>

An ordered collection (also known as a sequence) Unlike sets, lists typically allow duplicate elements.

Class LinkedList<E>

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>,


Deque<E>, Cloneable, Serializable

Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations,
and permits all elements (including null).

Constructors:

LinkedList(): Constructs an empty list.


LinkedList(Collection<? extends E> c): Constructs a list containing the elements of the
specified collection, in the order they are returned by the collection's iterator.

Class ArrayList<E>

public class ArrayList<E> extends AbstractList<E> implements List<E>,


RandomAccess, Cloneable, Serializable

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all
elements, including null.

Constructors:

ArrayList(): Constructs an empty list with an initial capacity of ten.


ArrayList(int initialCapacity): Constructs an empty list with the specified initial capacity.
ArrayList(Collection<? extends E> c): Constructs a list containing the elements of the specified
collection, in the order they are returned by the collection's iterator.

Interface Set<E>

5 / 27
NotesHassan.md 2024-02-06

public interface Set<E> extends Collection<E>

A collection that contains no duplicate elements.

Class HashSet<E>

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable,


Serializable

This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no
guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain
constant over time. This class permits the null element.

Constructors:

HashSet(): Constructs a new, empty set; the backing HashMap instance has default initial capacity (16)
and load factor (0.75).
HashSet(int initialCapacity): Constructs a new, empty set; the backing HashMap instance has
the specified initial capacity and default load factor (0.75).
HashSet(int initialCapacity, float loadFactor): Constructs a new, empty set; the backing
HashMap instance has the specified initial capacity and the specified load factor.
HashSet(Collection<? extends E> c): Constructs a new set containing the elements in the
specified collection.

Class TreeSet<E>

public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>,


Cloneable, Serializable

The elements are ordered using their natural ordering, or by a Comparator provided at set creation time,
depending on which constructor is used.

Constructors:

TreeSet(): Constructs a new, empty tree set, sorted according to the natural ordering of its elements.
TreeSet(Collection<? extends E> c): Constructs a new tree set containing the elements in the
specified collection, sorted according to the natural ordering of its elements.
TreeSet(Comparator<? super E> comparator): Constructs a new, empty tree set, sorted according
to the specified comparator.
TreeSet(SortedSet<E> s): Constructs a new tree set containing the same elements and using the
same ordering as the specified sorted set.

Interface Queue<E>

6 / 27
NotesHassan.md 2024-02-06

public interface Queue<E> extends Collection<E>

FIFO (First In, First Out) interface.

Interface Deque<E>

public interface Deque<E> extends Queue<E>

A linear collection that supports element insertion and removal at both ends.

Class PriorityQueue<E>

public class PriorityQueue<E> extends AbstractQueue<E> implements Serializable

An unbounded priority queue based on a priority heap. The elements of the priority queue are ordered
according to their natural ordering, or by a Comparator provided at queue construction time, depending on
which constructor is used. A priority queue does not permit null elements. A priority queue relying on natural
ordering also does not permit insertion of non-comparable objects (doing so may result in
ClassCastException).

Interface Map<K,V>

public interface Map<K,V>

An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one
value.

Nested Classes:

static interface Map.Entry<K,V>: A map entry (key-value pair).

Important Methods:

void clear(): Removes all of the mappings from this map (optional operation).
boolean containsKey(Object key): Returns true if this map contains a mapping for the specified
key.
boolean containsValue(Object value): Returns true if this map maps one or more keys to the
specified value.
Set<Map.Entry<K,V>> entrySet(): Returns a Set view of the mappings contained in this map.
V get(Object key): Returns the value to which the specified key is mapped, or null if this map
contains no mapping for the key.

7 / 27
NotesHassan.md 2024-02-06

int hashCode(): Returns the hash code value for this map.
boolean isEmpty(): Returns true if this map contains no key-value mappings.
Set<K> keySet(): Returns a Set view of the keys contained in this map.
V put(K key, V value): Associates the specified value with the specified key in this map (optional
operation).
void putAll(Map<? extends K, ? extends V> m): Copies all of the mappings from the specified
map to this map (optional operation).
V remove(Object key): Removes the mapping for a key from this map if it is present (optional
operation).
int size(): Returns the number of key-value mappings in this map.
Collection<V> values(): Returns a Collection view of the values contained in this map.

Updating Map Entries:

Get the old value associated with a key + update it + put back.

Example:

counts.put(word, counts.get(word) + 1);

This works except in the case when the word is encountered for the first time, get() returns null, and a
NullPointerException occurs. To remedy this, use getOrDefault method:

counts.put(word, counts.getOrDefault(word, 0) + 1);

Methods for 3 views:

1. Set<K> keySet(): set of keys Example:

Set keys = map.keySet();


for (String key : keys) { do something with key }

2. Collection values(): collection of values (which is not a set)


3. Set<Map.Entry<K,V>> entrySet(): set of key/value pairs Example:

for (Map.Entry<String, Employee> entry : staff.entrySet()) {


String key = entry.getKey();
Employee value = entry.getValue();
// do something with key, value
}

Remove & Add using Views:

8 / 27
NotesHassan.md 2024-02-06

remove(): removes key and its associated value from the map However, cannot add an element to key
set view. It makes no sense to add a key without also adding a value.
Entry set view has the same restriction even though it would make conceptual sense to add a new
key/value pair.

Class TreeMap<K,V>

public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>,


Cloneable, Serializable

A Red-Black tree based NavigableMap implementation. The map is sorted according to the natural ordering
of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.

Constructors:

TreeMap(): Constructs a new, empty tree map, using the natural ordering of its keys.
TreeMap(Comparator<? super K> comparator): Constructs a new, empty tree map, ordered
according to the given comparator.
TreeMap(Map<? extends K, ? extends V> m): Constructs a new tree map containing the same
mappings as the given map, ordered according to the natural ordering of its keys.
TreeMap(SortedMap<K, ? extends V> m): Constructs a new tree map containing the same
mappings and using the same ordering as the specified sorted map.

Class HashMap<K,V>

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable,


Serializable

Hash table based implementation of the Map interface. This implementation provides all of the optional map
operations, and permits null values and the null key.

Constructors:

HashMap(): Constructs an empty HashMap with the default initial capacity (16) and the default load
factor (0.75).
HashMap(int initialCapacity): Constructs an empty HashMap with the specified initial capacity
and the default load factor (0.75).
HashMap(int initialCapacity, float loadFactor): Constructs an empty HashMap with the
specified initial capacity and load factor.
HashMap(Map<? extends K, ? extends V> m): Constructs a new HashMap with the same mappings
as the specified Map.

Lambda Expressions in Java

9 / 27
NotesHassan.md 2024-02-06

Lambda expressions in Java provide a concise way to represent anonymous functions, making code more
readable and expressive. They are commonly used in functional-style programming and in passing behavior
as arguments to methods.

Syntax:

(parameter_list) -> { lambda_body }

Examples:

// Example 1: Simple lambda expression


() -> System.out.println("Hello, Lambda!");

// Example 2: Lambda expression with parameters


(int x, int y) -> { return x + y; }

// Example 3: Lambda expression with single parameter and implicit return


x -> x * x

Use in Sorting Collections:

Lambda expressions are often used with the Comparator interface for sorting collections in a more concise
and expressive manner.

Sorting with Lambda Expression:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Sort names alphabetically using lambda expression


names.sort((name1, name2) -> name1.compareTo(name2));

Stream API in Java

The Stream API in Java provides a powerful way to process collections of objects in a functional-style manner.
It allows for operations like filtering, mapping, reducing, and sorting on collections with ease.

Example:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Filter even numbers


List<Integer> evenNumbers = numbers.stream()

10 / 27
NotesHassan.md 2024-02-06

.filter(n -> n % 2 == 0)
.collect(Collectors.toList());

Key Stream Operations:

Filter: Selects elements based on a given predicate.


Map: Transforms each element to another using a given function.
Reduce: Aggregates elements into a single value using an associative function.
Collect: Converts the elements of a stream into a different form, such as a List, Set, or Map.
Sort: Orders elements based on a given comparator.

Use in Sorting Collections:

The Stream API provides convenient methods for sorting collections using lambda expressions.

Sorting with Stream API:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Sort names alphabetically using Stream API


List<String> sortedNames = names.stream()
.sorted((name1, name2) -> name1.compareTo(name2))
.collect(Collectors.toList());

By leveraging lambda expressions and the Stream API, Java developers can write more concise and readable
code for processing collections, making code maintenance and understanding easier.

Comparable and Comparator Interfaces in Java

In Java, the Comparable and Comparator interfaces provide mechanisms for sorting collections of objects
based on their natural ordering or custom sorting criteria.

Comparable Interface

The Comparable interface allows objects to define their natural ordering by implementing the compareTo
method. This interface is typically implemented by the class whose instances need to be sorted.

Example:

Suppose we have a Person class with a name field. We want to sort a collection of Person objects
alphabetically based on their names.

public class Person implements Comparable<Person> {


private String name;

public Person(String name) {

11 / 27
NotesHassan.md 2024-02-06

this.name = name;
}

public int compareTo(Person other) {


return this.name.compareTo(other.name);
}
}

In this example, the compareTo method compares Person objects based on their names.

Comparator Interface

The Comparator interface provides a way to define custom sorting logic separately from the class being
sorted. It allows for more flexible sorting, especially when dealing with classes that do not implement
Comparable or when multiple sorting criteria are needed.

Example:

Suppose we have a Student class with name and age fields. We want to sort a collection of Student objects
first by age and then by name.

import java.util.Comparator;

public class AgeNameComparator implements Comparator<Student> {


public int compare(Student s1, Student s2) {
int ageComparison = Integer.compare(s1.getAge(), s2.getAge());
if (ageComparison == 0) {
// If ages are the same, compare by name
return s1.getName().compareTo(s2.getName());
}
return ageComparison;
}
}

Sorting Collections

When sorting collections, objects can be sorted either using their natural ordering (if they implement
Comparable) or using a custom Comparator.

Sorting with Comparable:

List<Person> people = new ArrayList<>();


// Add Person objects to the list
Collections.sort(people);

Sorting with Comparator:

12 / 27
NotesHassan.md 2024-02-06

List<Student> students = new ArrayList<>();


// Add Student objects to the list
Comparator<Student> ageNameComparator = new AgeNameComparator();
Collections.sort(students, ageNameComparator);

Sure, let's provide an example for each design pattern:

Design Patterns

Creational Patterns

Singleton Pattern

Example: Logger class ensuring only one instance is used throughout the application.

public class Logger {


private static Logger instance;

private Logger() {
}

public static synchronized Logger getInstance() {


if (instance == null) {
instance = new Logger();
}
return instance;
}

public void log(String message) {


System.out.println("Logging: " + message);
}
}

Factory Method Pattern

Example: A factory producing different types of vehicles.

// Product interface
public interface Vehicle {
void drive();
}

// Concrete Products
public class Car implements Vehicle {
@Override
public void drive() {
System.out.println("Driving a car");

13 / 27
NotesHassan.md 2024-02-06

}
}

public class Truck implements Vehicle {


@Override
public void drive() {
System.out.println("Driving a truck");
}
}

// Creator
public abstract class VehicleFactory {
public abstract Vehicle createVehicle();
}

// Concrete Creator
public class CarFactory extends VehicleFactory {
@Override
public Vehicle createVehicle() {
return new Car();
}
}

public class TruckFactory extends VehicleFactory {


@Override
public Vehicle createVehicle() {
return new Truck();
}
}

Abstract Factory Pattern

Example: Abstract factory producing different families of related products.

// Abstract Product A
public interface Engine {
void producePower();
}

// Concrete Product A
public class GasolineEngine implements Engine {
@Override
public void producePower() {
System.out.println("Producing power with gasoline engine");
}
}

// Abstract Product B
public interface Wheel {
void rotate();
}

14 / 27
NotesHassan.md 2024-02-06

// Concrete Product B
public class RubberWheel implements Wheel {
@Override
public void rotate() {
System.out.println("Rubber wheel rotating");
}
}

// Abstract Factory
public interface VehicleFactory {
Engine createEngine();
Wheel createWheel();
}

// Concrete Factory
public class CarFactory implements VehicleFactory {
@Override
public Engine createEngine() {
return new GasolineEngine();
}

@Override
public Wheel createWheel() {
return new RubberWheel();
}
}

Prototype Pattern

Example: Cloning animals with slight variations.

// Prototype
public abstract class Animal implements Cloneable {
protected String name;

public abstract void makeSound();

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

// Concrete Prototypes
public class Dog extends Animal {
public Dog() {
this.name = "Dog";
}

@Override

15 / 27
NotesHassan.md 2024-02-06

public void makeSound() {


System.out.println("Woof!");
}
}

public class Cat extends Animal {


public Cat() {
this.name = "Cat";
}

@Override
public void makeSound() {
System.out.println("Meow!");
}
}

Structural Patterns

Adapter Pattern

Example: Real-time translator translating from English to French.

// Target interface
public interface EnglishSpeaker {
void speakEnglish();
}

// Adaptee
public class FrenchSpeaker {
public void parlerFrancais() {
System.out.println("Parler en Français");
}
}

// Adapter
public class FrenchTranslator implements EnglishSpeaker {
private FrenchSpeaker speaker;

public FrenchTranslator(FrenchSpeaker speaker) {


this.speaker = speaker;
}

@Override
public void speakEnglish() {
speaker.parlerFrancais();
}
}

Composite Pattern

16 / 27
NotesHassan.md 2024-02-06

Example: A company's organizational structure where departments contain employees and sub-departments.

// Component interface
public interface Department {
void showDepartmentDetails();
}

// Leaf
public class Employee implements Department {
private String name;

public Employee(String name) {


this.name = name;
}

@Override
public void showDepartmentDetails() {
System.out.println("Employee: " + name);
}
}

// Composite
public class DepartmentComposite implements Department {
private List<Department> departments = new ArrayList<>();

public void addDepartment(Department department) {


departments.add(department);
}

public void removeDepartment(Department department) {


departments.remove(department);
}

@Override
public void showDepartmentDetails() {
for (Department department : departments) {
department.showDepartmentDetails();
}
}
}

Bridge Pattern

Example: Different shapes drawn using different drawing methods.

// Abstraction
public abstract class Shape {
protected DrawingAPI drawingAPI;

protected Shape(DrawingAPI drawingAPI) {

17 / 27
NotesHassan.md 2024-02-06

this.drawingAPI = drawingAPI;
}

public abstract void draw();


}

// Implementor
public interface DrawingAPI {
void drawCircle(double x, double y, double radius);
}

// Concrete Implementor
public class DrawingAPI1 implements DrawingAPI {
@Override
public void drawCircle(double x, double y, double radius) {
System.out.printf("API1.circle at %f:%f radius %f%n", x, y, radius);
}
}

// Concrete Implementor
public class DrawingAPI2 implements DrawingAPI {
@Override
public void drawCircle(double x, double y, double radius) {
System.out.printf("API2.circle at %f:%f radius %f%n", x, y, radius);
}
}

// Refined Abstraction
public class CircleShape extends Shape {
private double x, y, radius;

public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {


super(drawingAPI);
this.x = x;
this.y = y;
this.radius = radius;
}

@Override
public void draw() {
drawingAPI.drawCircle(x, y, radius);
}
}

Flyweight Pattern

Example: Text editing where each character is represented as a flyweight object.

// Flyweight interface
public interface TextCharacter {
void draw(int fontSize);

18 / 27
NotesHassan.md 2024-02-06

// Concrete Flyweight
public class EnglishCharacter implements TextCharacter {
private char character;

public EnglishCharacter(char character) {


this.character = character;
}

@Override
public void draw(int fontSize) {
System.out.println("Drawing English character: " + character + " with font
size " + fontSize);
}
}

// Flyweight Factory
public class TextCharacterFactory {
private Map<Character, TextCharacter> characters = new HashMap<>();

public TextCharacter getCharacter(char character) {


characters.putIfAbsent(character, new EnglishCharacter(character));
return characters.get(character);
}
}

Proxy Pattern

Example: Protection proxy controlling access to a sensitive object.

// Subject interface
public interface SensitiveData {
void access();
}

// Real Subject
public class SensitiveDataImpl implements SensitiveData {
@Override
public void access() {
System.out.println("Accessing sensitive data");
}
}

// Proxy
public class Proxy implements SensitiveData {
private SensitiveData realSubject;
private String password;

public Proxy(String password) {


this.password = password;

19 / 27
NotesHassan.md 2024-02-06

this.realSubject = new SensitiveDataImpl();


}

@Override
public void access() {
if (password.equals("correctPassword")) {
realSubject.access();
} else {
System.out.println("Access denied");
}
}
}

Decorator Pattern

Example: Adding toppings to a pizza.

// Component interface
public interface Pizza {
String getDescription();
double getCost();
}

// Concrete Component
public class PlainPizza implements Pizza {
@Override
public String getDescription() {
return "Plain Pizza";
}

@Override
public double getCost() {
return

5.0;
}
}

// Decorator
public abstract class PizzaDecorator implements Pizza {
protected Pizza pizza;

public PizzaDecorator(Pizza pizza) {


this.pizza = pizza;
}

@Override
public String getDescription() {
return pizza.getDescription();
}

20 / 27
NotesHassan.md 2024-02-06

@Override
public double getCost() {
return pizza.getCost();
}
}

// Concrete Decorator
public class CheeseDecorator extends PizzaDecorator {
public CheeseDecorator(Pizza pizza) {
super(pizza);
}

@Override
public String getDescription() {
return pizza.getDescription() + ", Cheese";
}

@Override
public double getCost() {
return pizza.getCost() + 1.5;
}
}

Facade Pattern

Example: Complex process of booking a flight simplified into a single method call.

// Facade
public class FlightBookingFacade {
private HotelBooking hotelBooking;
private FlightBooking flightBooking;

public FlightBookingFacade() {
this.hotelBooking = new HotelBooking();
this.flightBooking = new FlightBooking();
}

public void bookFlightAndHotel() {


hotelBooking.bookHotel();
flightBooking.bookFlight();
}
}

Behavioral Patterns

Iterator Pattern

Example: Iterating over a collection of items without exposing its underlying representation.

21 / 27
NotesHassan.md 2024-02-06

// Aggregate interface
public interface Collection<T> {
Iterator<T> iterator();
}

// Concrete Aggregate
public class MyCollection<T> implements Collection<T> {
private List<T> items;

public MyCollection() {
this.items = new ArrayList<>();
}

public void add(T item) {


items.add(item);
}

@Override
public Iterator<T> iterator() {
return new MyIterator<>(items);
}
}

// Iterator interface
public interface Iterator<T> {
boolean hasNext();
T next();
}

// Concrete Iterator
public class MyIterator<T> implements Iterator<T> {
private List<T> items;
private int position;

public MyIterator(List<T> items) {


this.items = items;
this.position = 0;
}

@Override
public boolean hasNext() {
return position < items.size();
}

@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items.get(position++);
}
}

22 / 27
NotesHassan.md 2024-02-06

Observer Pattern

Example: A button listener in a user interface.

// Observer interface
public interface Observer {
void update();
}

// Subject
public class Button {
private List<Observer> observers = new ArrayList<>();

public void addObserver(Observer observer) {


observers.add(observer);
}

public void click() {


// Button click event
notifyObservers();
}

private void notifyObservers() {


for (Observer observer : observers) {
observer.update();
}
}
}

// Concrete Observer
public class ButtonClickListener implements Observer {
@Override
public void update() {
System.out.println("Button clicked!");
}
}

Mediator Pattern

Example: Chat server mediating communication between clients.

// Mediator
public interface ChatMediator {
void sendMessage(User user, String message);
}

// Concrete Mediator
public class ChatServer implements ChatMediator {
@Override
public void sendMessage(User user, String message) {
23 / 27
NotesHassan.md 2024-02-06

// Logic to broadcast message to other users


}
}

// Colleague
public class User {
private ChatMediator mediator;
private String name;

public User(ChatMediator mediator, String name) {


this.mediator = mediator;
this.name = name;
}

public void sendMessage(String message) {


mediator.sendMessage(this, message);
}
}

State Pattern

Example: Traffic light system changing behavior based on its current state.

// State interface
public interface TrafficLightState {
void change(TrafficLight light);
}

// Concrete States
public class RedLight implements TrafficLightState {
@Override
public void change(TrafficLight light) {
light.setState(new GreenLight());
}
}

public class GreenLight implements TrafficLightState {


@Override
public void change(TrafficLight light) {
light.setState(new YellowLight());
}
}

public class YellowLight implements TrafficLightState {


@Override
public void change(TrafficLight light) {
light.setState(new RedLight());
}
}

// Context

24 / 27
NotesHassan.md 2024-02-06

public class TrafficLight {


private TrafficLightState state;

public TrafficLight() {
this.state = new RedLight();
}

public void setState(TrafficLightState state) {


this.state = state;
}

public void change() {


state.change(this);
}
}

Strategy Pattern

Example: Different algorithms for sorting a collection.

// Strategy interface
public interface SortingStrategy<T extends Comparable<T>> {
void sort(List<T> items);
}

// Concrete Strategies
public class BubbleSort<T extends Comparable<T>> implements SortingStrategy<T> {
@Override
public void sort(List<T> items) {
// Bubble sort implementation
}
}

public class QuickSort<T extends Comparable<T>> implements SortingStrategy<T> {


@Override
public void sort(List<T> items) {
// Quick sort implementation
}
}

// Context
public class Sorter<T extends Comparable<T>> {
private SortingStrategy<T> strategy;

public Sorter(SortingStrategy<T> strategy) {


this.strategy = strategy;
}

public void setStrategy(SortingStrategy<T> strategy) {


this.strategy = strategy;
}

25 / 27
NotesHassan.md 2024-02-06

public void sort(List<T> items) {


strategy.sort(items);
}
}

Memento Pattern

Example: Saving and restoring a previous state of an object.

// Memento
public class Memento {
private String state;

public Memento(String state) {


this.state = state;
}

public String getState() {


return state;
}
}

// Originator
public class TextEditor {
private String text;

public void write(String text) {


this.text = text;
}

public Memento save() {


return new Memento(text);
}

public void restore(Memento memento) {


text = memento.getState();
}
}

// Caretaker
public class TextEditorHistory {
private Stack<Memento> history = new Stack<>();

public void save(Memento memento) {


history.push(memento);
}

public Memento undo() {


return history.pop();

26 / 27
NotesHassan.md 2024-02-06

}
}

27 / 27
Design Patterns Cheat Sheet
Creational Patterns Structural Patterns (cont’d)
Abstract Factory Bridge

Provides an interface for creating families of related or dependent objects without Decouples an abstraction from its implementation so that the two can vary
specifying their concrete classes independently
Abstraction
AbstractFactory ConcreteFactory Client
+Operation()
+CreateProductA() +CreateProductA()
+CreateProductB() +CreateProductB() ConcreteImplementorA

creates
Client +OperationImpl()
Implementor
ProductA
AbstractProduct +OperationImpl() ConcreteImplementorB
ProductB +OperationImpl()

Builder
Composite
Separates the construction of a complex object from its representation so that the
same construction process can create different representations. Composes objects into tree structures to represent part-whole hierarchies

Composite
Director Builder
+Operation()
+Construct() +BuildPart() +Add(component)
Component
+Remove(component)
+Operation() +GetChild(index)
Client +Add(component)
Product builds ConcreteBuilder +Remove(component)
+GetChild(index) Leaf
+BuildPart()
+Operation()

Factory Method
Decorator
Defines an interface for creating an object but let subclasses decide which class to
instantiate Attaches additional responsibilities to an object dynamically

Product Creator ConcreteComponent


+FactoryMethod() +Operation()
Component
+Operation() ConcreteDecorator
Decorator
ConcreteProduct creates ConcreteCreator +Operation()
+Operation() +AddedBehavior()
+FactoryMethod()

Prototype Facade

Specifies the kinds of objects to create using a prototypical instance and create new Provides a unified interface to a set of interfaces in a subsystem
objects by copying this prototype
Facade
ConcretePrototype1
+Clone()
Prototype
Client
+Clone() Subsystem
ConcretePrototype2
+Clone()
Flyweight

Singleton Uses sharing to support large numbers of fine-grained objects efficiently

Ensure a class only has one instance and provide a global point of access to it
FlyweightFactory
Client
+GetFlyweight(key)
Singleton
-instance UnsharedFlyweight
+Operation(state)
-Singleton() Flyweight
+GetInstance()
+Operation(state)
Flyweight
+Operation(state)
Structural Patterns
Adapter
Proxy
Converts the interface of a class into another interface clients expect
Provides a surrogate or placeholder for another object to control access to it

Target Proxy
Client
+Request() +Request()
Subject
Client
+Request()
Adapter Adaptee RealSubject
+Request() +SpecificRequest() +Request()
Design Patterns Cheat Sheet
Behavioral Patterns Behavioral Patterns (cont’d)
Chain of Responsibility Observer

Avoids coupling the sender of a request to its receiver by giving more than one object Defines a one-to-many dependency between objects so that when one object changes
a chance to handle the request state all its dependents are notified and updated automatically

ConcreteHandler1 Subject
Observer
+HandleRequest() +Attach(observer)
Handler +Detach(observer) +Update()
Client +Notify()
+HandleRequest()
ConcreteHandler2
+HandleRequest()
ConcreteSubject ConcreteObserver
-subjectState -observerState

Command +HandleRequest() +Update()

Encapsulates a request as an object, thereby letting you parameterize clients with


different requests, queue or log requests, and support undoable operations State

Client Invoker Allows an object to alter its behavior when its internal state changes

executes Context
+Request()
Receiver ConcreteCommand Command
+Action() +Execute() +Execute()
ConcreteStateA
+Handle()
State
Interpreter
+Handle()
ConcreteStateB
Given a language, defines a representation for its grammar along with an interpreter
that uses the representation to interpret sentences in the language +Handle()

Client Context
Strategy
TerminalExpression Defines a family of algorithms, encapsulate each one, and make them interchangeable
+Interpret(context)
AbstractExpression
+Interpret(context) Context
NonterminalExpression
+ContextInterface()
+Interpret(context)
StrategyA

Iterator +AlgorithmInterface()
Strategy

Given a language, defines a representation for its grammar along with an interpreter +AlgorithmInterface()
StrategyB
that uses the representation to interpret sentences in the language
+AlgorithmInterface()

Aggregate ConcreteAggregate
+CreateIterator() +CreateIterator() TemplateMethod

Client Defines the skeleton of an algorithm in an operation, deferring some steps to


subclasses
Iterator
ConcreteIterator
+First() AbstractClass
+Next() +Next() ConcreteClass
+CurrentItem() +TemplateMethod() +PrimitiveOperation1()
+PrimitiveOperation1() +PrimitiveOperation2()
+PrimitiveOperation2()
Mediator

Defines an object that encapsulates how a set of objects interact TemplateMethod

Represents an operation to be performed on the elements of an object structure


Mediator ConcreteMediator

Visitor ConcreteVisitor
ConcreteColleague1
Colleague +VisitElementA(element) +VisitElementA(element)
+VisitElementB(element) +VisitElementB(element)
ConcreteColleague2

Client ConcreteElementA
Memento +Accept(visitor)
Element
Without violating encapsulation, capture and externalize an object's internal state so +Accept(visitor)
that the object can be restored to this state later ConcreteElementB
+Accept(visitor)
Originator Memento
-state -state
Caretaker
+SetMemento(memento) +GetState()
+CreateMemento() +SetState()

You might also like