Object-Oriented Software Engineering

This is an archived version of https://www.jhu-oose.com that I (Leandro Facchinetti) developed when teaching the course in the Fall of 2019. Some of the links may be broken.

Lecture 9: Programming Paradigms

Video 🔒

Object-Oriented vs. Functional Programming

Here are two snippets of JavaScript implementing the same behavior:

class Rock {
  toString() {
    return "💎";
  }

  beats(otherPlayerChoice) {
    return otherPlayerChoice instanceof Scissors;
  }
}

class Paper {
  toString() {
    return "📄";
  }

  beats(otherPlayerChoice) {
    return otherPlayerChoice instanceof Rock;
  }
}

class Scissors {
  toString() {
    return "✂️";
  }

  beats(otherPlayerChoice) {
    return otherPlayerChoice instanceof Paper;
  }
}

const player1Choice = new Rock();
const player2Choice = new Scissors();

console.log(`Player 1 chose ${player1Choice}`);
console.log(`Player 2 chose ${player2Choice}`);
if (player1Choice.beats(player2Choice)) console.log("Player 1 wins!");
else if (player2Choice.beats(player1Choice)) console.log("Player 2 wins!");
else console.log("It’s a draw!");
Version 1
class Rock {}
class Paper {}
class Scissors {}

function toString(playerChoice) {
  if (playerChoice instanceof Rock) return "💎";
  if (playerChoice instanceof Paper) return "🧻";
  if (playerChoice instanceof Scissors) return "✂️";
}

function beats(thisPlayerChoice, otherPlayerChoice) {
  if (thisPlayerChoice instanceof Rock)
    return otherPlayerChoice instanceof Scissors;
  if (thisPlayerChoice instanceof Paper)
    return otherPlayerChoice instanceof Rock;
  if (thisPlayerChoice instanceof Scissors)
    return otherPlayerChoice instanceof Paper;
}

const player1Choice = new Rock();
const player2Choice = new Scissors();

console.log(`Player 1 chose ${toString(player1Choice)}`);
console.log(`Player 2 chose ${toString(player2Choice)}`);
if (beats(player1Choice, player2Choice)) console.log("Player 1 wins!");
else if (beats(player2Choice, player1Choice)) console.log("Player 2 wins!");
else console.log("It’s a draw!");
Version 2

Key Points

Object-Oriented Programming

Funcional Programming

Object-Oriented Programming in Depth

Typically people learn about object orientation in languages like Java, but there’s a lot more to it in other languages. We’ll continue to use JavaScript in this section, but many ideas here apply to other languages like Ruby, Python, Scala, and so forth.

Duck Typing

Consider our extension for choosing an option randomly:

class Rock {
  toString() {
    return "💎";
  }

  beats(otherPlayerChoice) {
    return otherPlayerChoice instanceof Scissors;
  }
}

class Paper {
  toString() {
    return "📄";
  }

  beats(otherPlayerChoice) {
    return otherPlayerChoice instanceof Rock;
  }
}

class Scissors {
  toString() {
    return "✂️";
  }

  beats(otherPlayerChoice) {
    return otherPlayerChoice instanceof Paper;
  }
}

function randomChoice() {
  const randomNumber = Math.random();
  if (randomNumber < 1 / 3) return new Rock();
  if (randomNumber < 2 / 3) return new Paper();
  if (randomNumber < 3 / 3) return new Scissors();
}

const player1Choice = randomChoice();
const player2Choice = randomChoice();

console.log(`Player 1 chose ${player1Choice}`);
console.log(`Player 2 chose ${player2Choice}`);
if (player1Choice.beats(player2Choice)) console.log("Player 1 wins!");
else if (player2Choice.beats(player1Choice)) console.log("Player 2 wins!");
else console.log("It’s a draw!");

Monkey Patching

For example:

class Rock {
  toString() {
    return "💎";
  }
}

const rock = new Rock();

Rock.prototype.toAscii = function() {
  return "rock";
};

rock.toString = function() {
  return "🐒";
};

console.log(`This ${rock.toAscii()}s!`);
console.log(`This ${rock}s!?`);

And:

Array.prototype.sample = function() {
  return this[Math.floor(Math.random() * this.length)];
};

console.log(["💎", "📄", "✂️"].sample());

Objects That Aren’t Instances of Classes

For example:

const rock = {
  toString() {
    return "💎";
  }
};

console.log(`This ${rock}s!`);

A Class is Just a Function That Constructs an Object

For example:

function Rock() {
  return {
    toString() {
      return "💎";
    }
  };
}

console.log(`This ${Rock()}s!`);

Classes are Values (Because They Really Are Just Functions, and Functions Are Values)

For example:

class Rock {}
class Paper {}
class Scissors {}

function randomChoice() {
  const randomNumber = Math.random();
  let ClassToInstantiate;
  if (randomNumber < 1 / 3) ClassToInstantiate = Rock;
  else if (randomNumber < 2 / 3) ClassToInstantiate = Paper;
  else if (randomNumber < 3 / 3) ClassToInstantiate = Scissors;
  return new ClassToInstantiate();
}

const player1Choice = randomChoice();

Mixins

For example:

class Rock {
  toString() {
    return "💎";
  }
}

function toDoubleStringMixin(Base) {
  return class extends Base {
    toDoubleString() {
      return `${this}${this}`;
    }
  };
}

const DoubleRock = toDoubleStringMixin(Rock);

const player1Choice = new DoubleRock();

console.log(player1Choice.toDoubleString());

Classes Don’t Have Parents; Objects Have Prototypes

We didn’t cover this in lecture.

class Rock {
  toString() {
    return "💎";
  }
}

class Paper {
  toString() {
    return "📄";
  }
}

const rock = new Rock();
rock.__proto__ = Paper.prototype;

console.log(`This ${rock}s!?`);

Functional Programming in Depth

We didn’t cover this in lecture.

Functions Are Values

Favor Immutability

Avoid Side-Effects

For example:

class Rock {}
class Paper {}
class Scissors {}

function beats(thisPlayerChoice, otherPlayerChoice) {
  if (thisPlayerChoice instanceof Rock)
    return otherPlayerChoice instanceof Scissors;
  if (thisPlayerChoice instanceof Paper)
    return otherPlayerChoice instanceof Rock;
  if (thisPlayerChoice instanceof Scissors)
    return otherPlayerChoice instanceof Paper;
}

let beaten = false;
function beatsViaSideEffects(thisPlayerChoice, otherPlayerChoice) {
  if (thisPlayerChoice instanceof Rock)
    beaten = otherPlayerChoice instanceof Scissors;
  else if (thisPlayerChoice instanceof Paper)
    beaten = otherPlayerChoice instanceof Rock;
  else if (thisPlayerChoice instanceof Scissors)
    beaten = otherPlayerChoice instanceof Paper;
}

Idempotence

Other Paradigms

Different programming paradigms exist to help you communicate different ideas more expressively. My favorite uncommon paradigm is relational programming.