What is Object-Orientation?
Abstraction: Ability to access objects while obscuring unnecessary details.
Simplifies code by hiding implementation complexities. This allows developers to focus on using objects without needing to understand their inner workings.
Polymorphism: Different classes implementing the same methods in their own ways.
Enables objects of different classes to respond to the same method call in a class-specific way. Example: A playSound()
method can produce a different sound depending on whether it is called on a Dog
object or a Cat
object.
Inheritance: Classes inheriting methods and properties from superclasses, promoting code reuse.
Creates a hierarchy of classes where common attributes and behaviors are defined in a superclass and inherited by subclasses. This reduces redundancy and facilitates code maintenance.
Encapsulation: Bundling methods and properties within classes.
Controls access to these properties (e.g., public
and private
in Java), preventing direct manipulation of internal data and ensuring data integrity.
Addresses the issue of sharing code between classes without using inheritance multiple times.
Encapsulates behavior into separate classes (strategies).
Allows algorithms to be selected at runtime.
Example: Animal attack behavior (biting or swooping).
Uses composition over inheritance.
Code Example: Animal and AttackBehavior
Animal
class has a myAttack
object of type AttackBehaviour
.
AttackBehaviour
is an interface with an attack()
method.
Concrete attack classes (PoisonBiteAttack
, SwoopAttack
) implement AttackBehaviour
.
Animal subclasses (e.g., Snake
, Eagle
) initialize myAttack
with specific attack behaviors.
This allows each animal to have different attack without needing distinct subclasses to implement attack.
interface AttackBehaviour {
void attack();
}
class PoisonBiteAttack implements AttackBehaviour {
public void attack() {
System.out.println("Bites with poison");
}
}
class Animal {
AttackBehaviour myAttack;
public Animal(AttackBehaviour attackType) {
this.myAttack = attackType;
}
public void doAttack() {
myAttack.attack();
}
}
class Snake extends Animal {
public Snake() {
super(new PoisonBiteAttack());
}
}
public class Main {
public static void main(String[] args) {
Animal snake = new Snake();
snake.doAttack(); // Output: Bites with poison
}
}
Strategy Pattern Diagram
Classes: Animal
, AttackBehaviour
, PoisonBiteAttack
, SwoopAttack
.
Animals use AttackBehaviour
to perform specific attacks.
A pattern offers a reusable solution to a common problem.
The "Gang of Four" book is a well-known pattern catalog.
Patterns are categorized as:
Behavioral: define object interactions and responsibility distribution.
Creational: concern object creation processes.
Structural: deal with object composition into larger systems.
Favor composition over inheritance.
Encapsulate what varies.
Program to an interface, not an implementation.
Name: Standard term for the pattern.
Classification: Pattern type (e.g., creational, behavioral).
Intent: Brief description of the pattern's purpose.
Motivation: Illustrative example of the pattern's usage.
Applicability: Scenarios where the pattern is suitable.
Structure: Class diagram representing participating classes.
Participants: Roles and responsibilities of the classes involved.
Collaborations: Interactions between classes and objects.
Consequences: Pros and cons of using the pattern.
Implementation: Techniques and considerations for implementation.
Sample Code: Code snippets demonstrating pattern implementation.
Known Uses: Real-world examples of the pattern in use.
Related Patterns: Similar or complementary patterns.
Creational:
Abstract Factory
Builder
Factory Method
Prototype
Singleton
Structural:
Adapter
Bridge
Composite
Decorator
Facade
Flyweight
Proxy
Behavioral:
Chain of Responsibility
Command
Interpreter
Iterator
Mediator
Memento
Observer
State
Strategy
Template Method
Visitor
Addresses issues with creating different environments (e.g., Jungle, Polar) without excessive code duplication.
Defines an interface for creating objects but lets subclasses alter the type of objects that will be created.
Problem Examples (Without Factory Method)
Multiple copies of environment setup code.
Conditional logic for environment creation, leading to code modification with each new environment type.
Class Diagram for Survival Environments (Factory Method Applied)
SurvivalGame
(abstract class) defines the environment setup.
JungleSurvival
and PolarSurvival
(subclasses) create specific patches and barriers.
Patch
and Barrier
(abstract classes) for segments of the environment.
Concrete classes: Jungle
, River
, Snow
, Crevasse
.
Code Example
SurvivalGame
has abstract methods createPatch()
and createBarrier()
.
Subclasses (JungleSurvival
, PolarSurvival
) implement these methods to return the correct type.
abstract class SurvivalGame {
public void setupEnvironment() {
Patch patch = createPatch();
Barrier barrier = createBarrier();
System.out.println("Setting up " + patch.getDescription() + " and " + barrier.getDescription());
}
abstract Patch createPatch();
abstract Barrier createBarrier();
}
class JungleSurvival extends SurvivalGame {
@Override
Patch createPatch() {
return new Jungle();
}
@Override
Barrier createBarrier() {
return new River();
}
}
public class Main {
public static void main(String[] args) {
SurvivalGame game = new JungleSurvival();
game.setupEnvironment(); // Output: Setting up Jungle and River
}
}
Design Principles in Factory Method Pattern
Open-Closed Principle: Classes should be open for extension but closed for modification.
New environments can be created without modifying existing code.
Concrete products are hidden from the creator class.
If the choice of factory is made at runtime, it becomes an Abstract Factory.
Addresses the issue of adding properties to objects dynamically.
Avoids class explosion by using composition instead of inheritance.
Allows adding responsibilities to objects without modifying their structure.
Problem Example (Without Decorator)
Creating multiple subclasses for each property combination (e.g., WingedSerpent, FireBreathingLizard).
Violates Open-Closed Principle because new properties requires modification to existing classes.
Class Diagram Using Decorator Pattern
AbstractAnimal
(implements Animal interface): Base class for animals.
Concrete animals: Hamster
, Serpent
, Lizard
etc.
AnimalDecorator
(abstract class): Implements Animal interface and holds a reference to Animal
.
Concrete decorators: Winged
, FireBreathing
.
Code Example
AnimalDecorator
implements the Animal
interface and holds an instance of another Animal which it decorates.
getDescription
and getWeight
methods are overridden in the Decorator to add functionality.
Example: Animal h = new FireBreathing(new Winged (new Hamster("H")))
interface Animal {
String getDescription();
int getWeight();
}
class Hamster implements Animal {
private String name;
public Hamster(String name) {
this.name = name;
}
@Override
public String getDescription() {
return name + " the Hamster";
}
@Override
public int getWeight() {
return 2;
}
}
abstract class AnimalDecorator implements Animal {
protected Animal animal;
public AnimalDecorator(Animal animal) {
this.animal = animal;
}
@Override
public String getDescription() {
return animal.getDescription();
}
@Override
public int getWeight() {
return animal.getWeight();
}
}
class Winged extends AnimalDecorator {
public Winged(Animal animal) {
super(animal);
}
@Override
public String getDescription() {
return animal.getDescription() + ", Winged";
}
@Override
public int getWeight() {
return animal.getWeight() + 1;
}
}
public class Main {
public static void main(String[] args) {
Animal h = new Winged(new Hamster("H"));
System.out.println(h.getDescription() + " weighs " + h.getWeight() + " lbs");
// Output: H the Hamster, Winged weighs 3 lbs
}
}
Key Aspects of Decorator Pattern
Dynamic addition of responsibilities.
Avoids class explosion due to inheritance.
Open-Closed Principle is maintained.
Decorator Pattern in Java API
java.io.InputStream
(Component).
java.io.FilterInputStream
(Decorator).
Decorators: java.io.BufferedInputStream
, java.io.CheckedInputStream
.
ConcreteComponent: java.io.FileInputStream
.
Favor composition over inheritance (Strategy, Abstract Factory)