Skip to content

Instantly share code, notes, and snippets.

@gemmadlou
Last active February 7, 2023 20:40
Show Gist options
  • Save gemmadlou/ca08fef90c0dfd68acfd to your computer and use it in GitHub Desktop.
Save gemmadlou/ca08fef90c0dfd68acfd to your computer and use it in GitHub Desktop.
Chain of Responsibility Pattern With Typescript - Adding Conditionals Together
/*
Example 01
Business Says
-------------
We only want scores of 4 and above
Developer Says
--------------
Simples. So we use an if statement.
*/
var scores = [
{ organiser: 's1', participant: 'p1', score: 3 },
{ organiser: 's1', participant: 'p2', score: 6 },
{ organiser: 's1', participant: 'p3', score: 4 },
{ organiser: 's2', participant: 'p1', score: 4 },
{ organiser: 's2', participant: 'p2', score: 0 },
{ organiser: 's2', participant: 'p3', score: 1 }
]
var acceptedScores = [];
for (var n = 0; n < scores.length; n++) {
if (scores[n].score >= 4) {
acceptedScores.push(scores[n]);
}
}
for (var i in acceptedScores) {
document.write(acceptedScores[i].organiser + ' - ' +
acceptedScores[i].participant + ' - ' +
acceptedScores[i].score + '<br>');
}
/*
Example 02
Business Says
-------------
We want scores of 4 and above only
And also scores that are a multiple of 3
Developer Says
--------------
Simples. So we use an if statement again. Just add the
new condition.
*/
var scores = [
{ organiser: 's1', participant: 'p1', score: 3 },
{ organiser: 's1', participant: 'p2', score: 6 },
{ organiser: 's1', participant: 'p3', score: 4 },
{ organiser: 's2', participant: 'p1', score: 4 },
{ organiser: 's2', participant: 'p2', score: 0 },
{ organiser: 's2', participant: 'p3', score: 1 }
]
var acceptedScores = [];
for (var n = 0; n < scores.length; n++) {
if (scores[n].score >= 4
&& scores[n].score % 3 === 0) {
acceptedScores.push(scores[n]);
}
}
for (var i in acceptedScores) {
document.write(acceptedScores[i].organiser + ' - ' +
acceptedScores[i].participant + ' - ' +
acceptedScores[i].score + '<br>');
}
/**
* Example 03
*
* Business Says
* -------------
* We may have more requirements in future.
* And we want to mix and match requirements too.
* From the User Interface please.
*
* Developer Says
* ---------------
* Instead of hard-coding the if statement, we can use
* the chain of responsibility pattern to dynamically add
* conditions at run time.
*
* We can also add more business requirements later by
* creating a new class to handle the condition.
*
* Extra Note
* ----------
* This example doesn't handle the array in any way special, but
* you would probably manipulate this array, or return something else
* completely.
*/
/**
* Typescript allows us to create interfaces
*/
interface ScoreInterface {
organiser: string;
participant: string;
score: number;
}
/**
* Which we can use to ensure we have the
* correct properties for our Score class
*/
class Score implements ScoreInterface {
organiser: string;
participant: string;
score: number;
constructor(organiser: string, participant: string, score: number) {
this.organiser = organiser;
this.participant = participant;
this.score = score;
}
}
/**
* The handler interface requires 3 things
* 1. a handle method. You can pass it anything you want - but
* whatever you pass it has to go through every other handler.
* In this example, I'm using scores.
*
* 2. a handler property. This references the next handler class
* in the chain of handlers.
*
* 3. a addHandler method. This allows you to add handlers separate from
* class instantiation.
*/
interface HandlerInterface {
handler: HandlerInterface;
handle(scores: ScoreInterface[]);
addHandler(handler: HandlerInterface);
}
class AboveScoreHandler implements HandlerInterface {
minimumscore: number;
handler: HandlerInterface;
constructor(minimumscore?: number) {
this.minimumscore = (typeof minimumscore === 'undefined') ? 0 : minimumscore;
}
handle(scores: ScoreInterface[]) {
if (scores[0].score < this.minimumscore) {
return false;
} else {
if (typeof this.handler !== 'undefined') {
return this.handler.handle(scores);
} else {
return true;
}
}
}
addHandler(handler: HandlerInterface) {
this.handler = handler;
}
}
var scores = [
new Score('s1', 'p1', 3),
new Score('s1', 'p2', 6),
new Score('s1', 'p3', 4),
new Score('s2', 'p1', 4),
new Score('s2', 'p2', 0),
new Score('s2', 'p3', 1)
]
var acceptedScores: ScoreInterface[] = [];
while (scores.length > 0) {
var handler = new AboveScoreHandler(4);
if (handler.handle(scores)) {
acceptedScores.push(scores[0]);
}
scores.splice(0, 1);
}
for (var i in acceptedScores) {
document.write(acceptedScores[i].organiser + ' - ' +
acceptedScores[i].participant + ' - ' +
acceptedScores[i].score + '<br>');
}
/**
* Example Final
*
* Now we can create new handler classes, and chain them
* together to get the same results.
*/
interface ScoreInterface {
organiser: string;
participant: string;
score: number;
}
class Score implements ScoreInterface {
organiser: string;
participant: string;
score: number;
constructor(organiser: string, participant: string, score: number) {
this.organiser = organiser;
this.participant = participant;
this.score = score;
}
}
interface HandlerInterface {
handler: HandlerInterface;
handle(scores: ScoreInterface[]);
addHandler(handler: HandlerInterface);
}
class HandlerAbstractClass implements HandlerInterface {
handler: HandlerInterface;
handle(scores: ScoreInterface[]) {
if (typeof this.handler !== 'undefined') {
return this.handler.handle(scores);
} else {
return false;
}
}
addHandler(handler: HandlerInterface) {
this.handler = handler;
}
}
class AboveScoreHandler extends HandlerAbstractClass implements HandlerInterface {
minimumscore: number;
handler: HandlerInterface;
constructor(minimumscore?: number) {
super();
this.minimumscore = (typeof minimumscore === 'undefined') ? 0 : minimumscore;
}
handle(scores: ScoreInterface[]) {
if (scores[0].score < this.minimumscore) {
return false;
} else {
if (typeof this.handler !== 'undefined') {
return this.handler.handle(scores);
} else {
return true;
}
}
}
}
class MultiplesOfHandler extends HandlerAbstractClass implements HandlerInterface {
multiples: number;
handler: HandlerInterface;
constructor(multiples?: number) {
super();
this.multiples = (typeof multiples === 'undefined') ? 1 : multiples;
}
handle(scores: ScoreInterface[]) {
if (scores[0].score % this.multiples !== 0) {
return false;
} else {
if (typeof this.handler !== 'undefined') {
return this.handler.handle(scores);
} else {
return true;
}
}
}
}
var scores = [
new Score('s1', 'p1', 3),
new Score('s1', 'p2', 6),
new Score('s1', 'p3', 4),
new Score('s2', 'p1', 4),
new Score('s2', 'p2', 0),
new Score('s2', 'p3', 1)
]
var acceptedScores: ScoreInterface[] = [];
while (scores.length > 0) {
/** Wiring up our handlers */
var handler = new AboveScoreHandler(4);
var handler2 = new MultiplesOfHandler(3);
handler.addHandler(handler2);
if (handler.handle(scores)) {
acceptedScores.push(scores[0]);
}
scores.splice(0, 1);
}
for (var i in acceptedScores) {
document.write(acceptedScores[i].organiser + ' - ' +
acceptedScores[i].participant + ' - ' +
acceptedScores[i].score + '<br>');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment